From 2577c614d54b035670f0a7a696f1a2c7de51ba27 Mon Sep 17 00:00:00 2001 From: chen-xin-zhi <3588068430@qq.com> Date: Thu, 24 Apr 2025 11:49:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=97=E5=BC=80=E5=BE=97=E8=83=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 35 +++++ .../annotation/RequiresPermission.java | 15 ++ .../promotion/aop/PermissionCheck.java | 132 ++++++++++++++++++ .../controller/user/UserController.java | 10 +- .../wechat/WechatGetQrcodeController.java | 2 +- .../greenorange/promotion/utils/JWTUtils.java | 40 ++++++ .../promotion/utils/codec/sendsms.java | 72 ++++++++++ src/main/resources/application.yml | 12 +- .../GreenOrangeApplicationTests.java | 7 + .../com/greenorange/promotion/JwtDemo.java | 47 +++++++ 10 files changed, 362 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/greenorange/promotion/annotation/RequiresPermission.java create mode 100644 src/main/java/com/greenorange/promotion/aop/PermissionCheck.java create mode 100644 src/main/java/com/greenorange/promotion/utils/JWTUtils.java create mode 100644 src/main/java/com/greenorange/promotion/utils/codec/sendsms.java create mode 100644 src/test/java/com/greenorange/promotion/JwtDemo.java diff --git a/pom.xml b/pom.xml index f38a3dc..4af5bd7 100644 --- a/pom.xml +++ b/pom.xml @@ -143,6 +143,41 @@ + + + com.aliyun + aliyun-java-sdk-core + 4.5.16 + + + + com.aliyun + aliyun-java-sdk-dysmsapi + 2.1.0 + + + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + + + org.dom4j + dom4j + 2.1.3 + + + + + com.auth0 + java-jwt + 3.14.0 + + diff --git a/src/main/java/com/greenorange/promotion/annotation/RequiresPermission.java b/src/main/java/com/greenorange/promotion/annotation/RequiresPermission.java new file mode 100644 index 0000000..e710610 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/annotation/RequiresPermission.java @@ -0,0 +1,15 @@ +package com.greenorange.promotion.annotation; + +import java.lang.annotation.*; + +/** + * JWT 权限注解 + **/ + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RequiresPermission { + String roles() default " "; + String permissions() default " "; +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java b/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java new file mode 100644 index 0000000..2d7b8e1 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java @@ -0,0 +1,132 @@ +package com.greenorange.promotion.aop; + +import cn.hutool.core.util.StrUtil; +import com.auth0.jwt.JWT; +import com.auth0.jwt.exceptions.JWTDecodeException; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.greenorange.promotion.annotation.RequiresPermission; +import com.greenorange.promotion.model.entity.User; +import com.greenorange.promotion.service.user.UserService; +import com.wechat.pay.java.core.exception.ServiceException; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +/** + * 权限校验AOP + */ + +@Slf4j +@Aspect +@Component +public class PermissionCheck { + + + @Resource + private UserService userService; + + + /*** + * @MethodName: permissionCheckPointCut + * @description: 定义一个切点 + * @Author: LiuTao + * @UpdateTime: 2023/6/20 19:34 + **/ + @Pointcut("@annotation(com.greenorange.promotion.annotation.RequiresPermission)") + public void permissionCheckPointCut() { + + } + + /*** + * @MethodName: check + * @description: 环绕通知 + * @Author: LiuTao + * @Param: [pjp] + * @UpdateTime: 2023/6/20 19:34 + * @Return: java.lang.Object + * @Throw: Throwable + **/ + @Around("permissionCheckPointCut()") + public Object check(ProceedingJoinPoint pjp) throws Throwable { + // 获取请求对象 + HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); + // 记录日志 + log.info("===============系统操作日志==============="); + Signature signature = pjp.getSignature(); + // 请求的类 + String className = pjp.getTarget().getClass().getName(); + String methodName = signature.getName(); + log.info("请求类:{}", className); + log.info("请求方法:{}", methodName); + log.info("请求方式:{}", request.getMethod()); + log.info("请求ip:{}", request.getRemoteAddr()); + log.info("请求类方法:{}", signature); + log.info("请求参数:{}", Arrays.toString(pjp.getArgs())); + // 权限注解校验 + MethodSignature handlerMethod = (MethodSignature) signature; + Method method = handlerMethod.getMethod(); + System.out.println("method:" + method); + System.out.println("-------------------------------------------"); + // 判断当前方法上有没有注解 + System.out.println(method.isAnnotationPresent(RequiresPermission.class)); + System.out.println("-------------------------------------------"); + + if (method.isAnnotationPresent(RequiresPermission.class)) { + RequiresPermission auth = method.getAnnotation(RequiresPermission.class); + System.out.println("++++++++++++++++++++++++++++auth:" + auth); + String roles = auth.roles(); + String permissions = auth.permissions(); + + String token = request.getHeader("token"); + // 认证 + if (StrUtil.isBlank(token)) { +// throw new ServiceException(Constants.CODE_401, "请登录!!!"); + } + String id = null; +// try { +// id = JWT.decode(token).getAudience().get(0); +// } catch (JWTDecodeException jwtDecodeException) { +//// throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录"); +// } +// User user = userService.getById(id); + // 校验角色 +// if (StrUtil.isNotBlank(roles)) { +// if (!Arrays.asList(roles.split(",")).contains(user.getRole())) { +//// throw new ServiceException(Constants.CODE_403, "当前角色权限不足"); +// } +// } + // 校验权限 +// if (StrUtil.isNotBlank(permissions)) { +// List userPermissions = menuUtil +// .getPermissions(user.getRole()) +// .stream() +// .map(BtnVo::getPermission) +// .collect(Collectors.toList()); +// if (!new HashSet<>(userPermissions).containsAll(Arrays.asList(permissions.split(",")))) { +// throw new ServiceException(Constants.CODE_401, "无权限访问资源"); +// } +// } + } + return pjp.proceed(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/controller/user/UserController.java b/src/main/java/com/greenorange/promotion/controller/user/UserController.java index 64370ab..dacf68e 100644 --- a/src/main/java/com/greenorange/promotion/controller/user/UserController.java +++ b/src/main/java/com/greenorange/promotion/controller/user/UserController.java @@ -1,7 +1,7 @@ package com.greenorange.promotion.controller.user; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.greenorange.promotion.annotation.AuthCheck; +import com.greenorange.promotion.annotation.RequiresPermission; import com.greenorange.promotion.common.BaseResponse; import com.greenorange.promotion.common.ResultUtils; import com.greenorange.promotion.constant.UserConstant; @@ -42,7 +42,7 @@ public class UserController { */ @PostMapping("add") @Operation(summary = "web端管理员添加用户", description = "参数:用户表添加请求体,权限:管理员(boss, admin),方法名:addUser") - @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + @RequiresPermission(roles = UserConstant.ADMIN_ROLE) public BaseResponse addUser(@RequestBody UserAddRequest userAddRequest) { return ResultUtils.success(userService.addUser(userAddRequest)); } @@ -81,8 +81,9 @@ public class UserController { */ @PostMapping("page") @Operation(summary = "Web端管理员分页查看用户表", description = "参数:用户表查询请求体,权限:管理员(boss, admin),方法名:listUserByPage") - public BaseResponse> listUserByPage(@RequestBody UserQueryRequest userQueryRequest) { - return ResultUtils.success(userService.listUserByPage(userQueryRequest)); + @RequiresPermission(roles = UserConstant.ADMIN_ROLE) + public BaseResponse listUserByPage(@RequestBody UserQueryRequest userQueryRequest) { + return ResultUtils.success(true); } @@ -110,4 +111,5 @@ public class UserController { public BaseResponse delBatchUser(@RequestBody CommonBatchRequest commonBatchRequest) { return ResultUtils.success(userService.delBatchUser(commonBatchRequest)); } + } diff --git a/src/main/java/com/greenorange/promotion/controller/wechat/WechatGetQrcodeController.java b/src/main/java/com/greenorange/promotion/controller/wechat/WechatGetQrcodeController.java index 26f3bb8..bb0ba26 100644 --- a/src/main/java/com/greenorange/promotion/controller/wechat/WechatGetQrcodeController.java +++ b/src/main/java/com/greenorange/promotion/controller/wechat/WechatGetQrcodeController.java @@ -75,7 +75,7 @@ public class WechatGetQrcodeController { */ @PostMapping("/get/qrcode") @Operation(summary = "微信小程序获取二维码", description = "参数:无, 权限:所有人, 方法名:getQrcode") - public BaseResponse getQrcode(HttpServletRequest request) throws IOException { + public BaseResponse getQrcode() throws IOException { String accessToken = (String) redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY); if (accessToken == null) { accessToken = wechatGetQrcodeService.getAccessToken().getAccess_token(); diff --git a/src/main/java/com/greenorange/promotion/utils/JWTUtils.java b/src/main/java/com/greenorange/promotion/utils/JWTUtils.java new file mode 100644 index 0000000..a252293 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/utils/JWTUtils.java @@ -0,0 +1,40 @@ +package com.greenorange.promotion.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTCreator; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; + +import java.util.Calendar; +import java.util.Map; + +public class JWTUtils { + + /** + * 生成token header.payload.signature + */ + private static final String SECRET = "qingcheng"; + + public static String getToken(Map map) { + + Calendar instance = Calendar.getInstance(); + // 默认7天过期 + instance.add(Calendar.DATE, 7); + + //创建jwt builder + JWTCreator.Builder builder = JWT.create(); + + // payload + map.forEach(builder::withClaim); + return builder.withExpiresAt(instance.getTime()) //指定令牌过期时间 + .sign(Algorithm.HMAC256(SECRET)); + } + + /** + * 验证token 合法性 + */ + public static DecodedJWT verify(String token) { + return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token); + } +} + diff --git a/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java b/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java new file mode 100644 index 0000000..17ef394 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java @@ -0,0 +1,72 @@ +package com.greenorange.promotion.utils.codec; + +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; + +import java.util.ArrayList; +import java.util.List; + +public class sendsms { + + private static String Url = "http://106.ihuyi.com/webservice/sms.php?method=Submit"; + + public static void main(String[] args) { + + // 创建 HttpClient + try (CloseableHttpClient client = HttpClients.createDefault()) { + // 创建 POST 请求 + HttpPost post = new HttpPost(Url); + post.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=GBK"); + + // 生成验证码 +// int mobile_code = (int) ((Math.random() * 9 + 1) * 100000); + int mobile_code = 114514; + String content = "您的验证码是:" + mobile_code + "。请不要把验证码泄露给其他人。"; + + // 设置请求参数 + List data = new ArrayList<>(); + data.add(new BasicNameValuePair("account", "C08121984")); + data.add(new BasicNameValuePair("password", "84a27a879413ec629bf26c5d84a25271")); + data.add(new BasicNameValuePair("mobile", "19804561639")); + data.add(new BasicNameValuePair("content", content)); + + // 设置请求体 + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(data, "GBK"); + post.setEntity(entity); + + // 执行请求 + String response = client.execute(post, httpResponse -> { + HttpEntity entity1 = httpResponse.getEntity(); + return EntityUtils.toString(entity1, "GBK"); + }); + + // 解析返回的 XML 响应 + Document doc = DocumentHelper.parseText(response); + Element root = doc.getRootElement(); + + String code = root.elementText("code"); + String msg = root.elementText("msg"); + String smsid = root.elementText("smsid"); + + System.out.println(code); + System.out.println(msg); + System.out.println(smsid); + + if ("2".equals(code)) { + System.out.println("短信提交成功"); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f64c7a2..7bf1d85 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,9 +1,9 @@ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://8.130.119.119:3306/qingcheng?serverTimezone=Asia/Shanghai + url: jdbc:mysql://1.94.237.210:3306/qingcheng?serverTimezone=Asia/Shanghai username: qingcheng - password: qingcheng + password: Qc@123456 hikari: maximum-pool-size: 20 max-lifetime: 120000 @@ -14,9 +14,11 @@ spring: data: redis: port: 6379 - host: 123.249.108.160 - database: 0 - password: yuanteng + host: 154.8.193.216 + database: 9 + password: Cksys6509 + + servlet: multipart: max-file-size: 20MB diff --git a/src/test/java/com/greenorange/promotion/GreenOrangeApplicationTests.java b/src/test/java/com/greenorange/promotion/GreenOrangeApplicationTests.java index bbd5e6f..6d898f0 100644 --- a/src/test/java/com/greenorange/promotion/GreenOrangeApplicationTests.java +++ b/src/test/java/com/greenorange/promotion/GreenOrangeApplicationTests.java @@ -1,13 +1,20 @@ package com.greenorange.promotion; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import java.util.Calendar; +import java.util.HashMap; + @SpringBootTest class GreenOrangeApplicationTests { @Test void contextLoads() { + + } } diff --git a/src/test/java/com/greenorange/promotion/JwtDemo.java b/src/test/java/com/greenorange/promotion/JwtDemo.java new file mode 100644 index 0000000..9b11897 --- /dev/null +++ b/src/test/java/com/greenorange/promotion/JwtDemo.java @@ -0,0 +1,47 @@ +package com.greenorange.promotion; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; + +import com.auth0.jwt.interfaces.JWTVerifier; +import org.junit.jupiter.api.Test; + +import java.util.Calendar; +import java.util.HashMap; + +public class JwtDemo { + + @Test + public void test() { + + HashMap map = new HashMap<>(); + + Calendar instance = Calendar.getInstance(); + // 20秒后令牌token失效 + instance.add(Calendar.HOUR,1); + + String token = JWT.create() + .withHeader(map) // header可以不写,因为默认值就是它 + .withClaim("userId", 21) //payload + .withClaim("username", "xiaoshuang") + .withExpiresAt(instance.getTime()) // 指定令牌的过期时间 + .sign(Algorithm.HMAC256("XIAOSHUANG"));//签名 + + System.out.println(token); + } + + @Test + public void testVerifier(){ + // 通过签名生成验证对象 + JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("XIAOSHUANG")).build(); + + DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NDU0NjE4NDYsInVzZXJJZCI6MjEsInVzZXJuYW1lIjoieGlhb3NodWFuZyJ9.oN1KdeASH4yqjJBn4hb9jux_VWXWXRz9DSE81RML9Ak"); + System.out.println(verify.getClaim("userId")); + System.out.println(verify.getClaim("username")); + System.out.println("令牌过期时间:"+verify.getExpiresAt()); + + } + + +}