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());
+
+ }
+
+
+}