Просмотр исходного кода

:point_up: JWT参数注解注入,通过反射生成/解析jwt

nnkwrik 6 лет назад
Родитель
Сommit
8590ecdde1

+ 0 - 5
auth-service/pom.xml

@@ -66,11 +66,6 @@
             <version>0.0.1-SNAPSHOT</version>
         </dependency>
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-amqp</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-stream-binder-rabbit</artifactId>

+ 12 - 19
auth-service/src/main/java/io/github/nnkwrik/authservice/token/TokenCreator.java

@@ -1,6 +1,7 @@
 package io.github.nnkwrik.authservice.token;
 
 import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTCreator;
 import com.auth0.jwt.algorithms.Algorithm;
 import com.auth0.jwt.interfaces.RSAKeyProvider;
 import io.github.nnkwrik.common.dto.JWTUser;
@@ -9,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import java.lang.reflect.Field;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 import java.time.Instant;
@@ -47,32 +49,23 @@ public class TokenCreator {
         }
     };
 
-    public String create(JWTUser jwtUser) {
+    public String create(JWTUser jwtUser) throws IllegalAccessException {
         Algorithm algorithm = Algorithm.RSA256(keyProvider);
         //一天后过期
         Date expire = Date.from(Instant.now().plus(1, ChronoUnit.DAYS));
 
-        String token = JWT.create()
-                .withClaim("openId", jwtUser.getOpenId())
-                .withClaim("nickName", jwtUser.getNickName())
-                .withClaim("avatarUrl", jwtUser.getAvatarUrl())
-                .withExpiresAt(expire)
-                .sign(algorithm);
+        JWTCreator.Builder builder = JWT.create();
 
-        return "Bearer " + token;
-    }
+        //通过反射构造token字符串
+        for (Field field : jwtUser.getClass().getDeclaredFields()) {
+            field.setAccessible(true);
+            String value = (String) field.get(jwtUser);
+            String name = field.getName();
+            builder.withClaim(name, value);
+        }
 
-    public String create(String openId, String nickName, String avatarUrl) {
-        Algorithm algorithm = Algorithm.RSA256(keyProvider);
-        //一天后过期
-        Date expire = Date.from(Instant.now().plus(1, ChronoUnit.DAYS));
+        String token = builder.withExpiresAt(expire).sign(algorithm);
 
-        String token = JWT.create()
-                .withClaim("openId", openId)
-                .withClaim("nickName", nickName)
-                .withClaim("avatarUrl", avatarUrl)
-                .withExpiresAt(expire)
-                .sign(algorithm);
 
         return "Bearer " + token;
     }

+ 3 - 3
auth-service/src/test/java/io/github/nnkwrik/authservice/jwt/GenerateToken.java

@@ -23,9 +23,9 @@ public class GenerateToken {
      * 生产环境下可以用这个生成Token进行测试
      */
     @Test
-    public void generateToken(){
-        String openId = "1212";
-        String nickName = "nickname";
+    public void generateToken() throws IllegalAccessException {
+        String openId = "1";
+        String nickName = "测试用户";
         String avatarUrl = "https://avatars2.githubusercontent.com/u/29662114?s=460&v=4";
 
         JWTUser jwtUser = new JWTUser(openId,nickName,avatarUrl);

+ 2 - 2
auth-service/src/test/java/io/github/nnkwrik/authservice/jwt/TestToken.java

@@ -32,14 +32,14 @@ public class TestToken {
 
 
     @Test
-    public void testToken(){
+    public void testToken() throws Exception {
         //测试注入密钥文件名
         System.out.println(pubFile);
         System.out.println(pvtFile);
 
         JWTUser jwtUser = new JWTUser();
         jwtUser.setOpenId("1212");
-        jwtUser.setNickName("nickName");
+        jwtUser.setNickname("nickName");
 
 
         //找到resource目录下的私钥文件后生成Token

+ 2 - 2
common/src/main/java/io/github/nnkwrik/common/dto/JWTUser.java

@@ -14,8 +14,8 @@ import lombok.NoArgsConstructor;
 public class JWTUser {
 
     private String openId;
-    private String nickName;
-    private String avatarUrl;
+    private String nickname;
+    private String avatar;
 
 
 }

+ 11 - 4
common/src/main/java/io/github/nnkwrik/common/token/TokenSolver.java

@@ -7,9 +7,12 @@ import com.auth0.jwt.interfaces.RSAKeyProvider;
 import io.github.nnkwrik.common.dto.JWTUser;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
 
+import java.lang.reflect.Field;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
 
 /**
  * @author nnkwrik
@@ -42,16 +45,20 @@ public class TokenSolver {
         }
     };
 
-    public JWTUser solve(String token) {
+    public JWTUser solve(String token) throws Exception {
+        if (StringUtils.isEmpty(token)) return null;
         token = token.replace("Bearer ", "");
         Algorithm algorithm = Algorithm.RSA256(keyProvider);
         //会自动验证过期时间
         DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
         JWTUser jwtUser = new JWTUser();
 
-        jwtUser.setOpenId(decodedJWT.getClaim("openId").asString());
-        jwtUser.setNickName(decodedJWT.getClaim("nickName").asString());
-        jwtUser.setAvatarUrl(decodedJWT.getClaim("avatarUrl").asString());
+        //通过反射构造JWTUser对象
+        for (Field field : jwtUser.getClass().getDeclaredFields()) {
+            String value = decodedJWT.getClaim(field.getName()).asString();
+            field.setAccessible(true);
+            field.set(jwtUser, value);
+        }
 
         return jwtUser;
     }

+ 14 - 0
common/src/main/java/io/github/nnkwrik/common/token/injection/JWT.java

@@ -0,0 +1,14 @@
+package io.github.nnkwrik.common.token.injection;
+
+import java.lang.annotation.*;
+
+/**
+ * @author nnkwrik
+ * @date 18/11/24 9:54
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JWT {
+
+    boolean required() default true;
+}

+ 54 - 0
common/src/main/java/io/github/nnkwrik/common/token/injection/JWTResolver.java

@@ -0,0 +1,54 @@
+package io.github.nnkwrik.common.token.injection;
+
+import com.auth0.jwt.exceptions.TokenExpiredException;
+import io.github.nnkwrik.common.dto.JWTUser;
+import io.github.nnkwrik.common.token.TokenSolver;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+/**
+ * @author nnkwrik
+ * @date 18/11/24 9:43
+ */
+@Slf4j
+@Component
+public class JWTResolver implements HandlerMethodArgumentResolver {
+
+    @Autowired
+    private TokenSolver tokenSolver;
+
+
+    @Override
+    public boolean supportsParameter(MethodParameter parameter) {
+        return parameter.getParameterAnnotation(JWT.class) != null;
+    }
+
+    @Override
+    public Object resolveArgument(MethodParameter parameter,
+                                  ModelAndViewContainer mavContainer,
+                                  NativeWebRequest webRequest,
+                                  WebDataBinderFactory binderFactory) {
+        String token = webRequest.getHeader("Authorization");
+        if (token == null) {
+            log.info("用户的Authorization头为空,无法获取jwt");
+            return null;
+        }
+        JWTUser user = null;
+        try {
+            user = tokenSolver.solve(token);
+        } catch (TokenExpiredException e) {
+            log.info("jwt已过期,过期时间:{}", e.getMessage());
+        } catch (Exception e) {
+            log.info("jwt解析失败");
+        }
+        log.info("jwt解析结果为:{}", user);
+        return user;
+    }
+
+}

+ 23 - 0
common/src/main/java/io/github/nnkwrik/common/token/injection/SolverConfig.java

@@ -0,0 +1,23 @@
+package io.github.nnkwrik.common.token.injection;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.util.List;
+
+/**
+ * @author nnkwrik
+ * @date 18/11/24 10:03
+ */
+@Configuration
+public class SolverConfig implements WebMvcConfigurer {
+
+    @Autowired
+    private JWTResolver jwtResolver;
+    @Override
+    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
+        resolvers.add(jwtResolver);
+    }
+}

+ 66 - 0
goods-service/src/main/java/io/github/nnkwrik/goodsservice/controller/TestController.java

@@ -0,0 +1,66 @@
+package io.github.nnkwrik.goodsservice.controller;
+
+import io.github.nnkwrik.common.dto.JWTUser;
+import io.github.nnkwrik.common.dto.Response;
+import io.github.nnkwrik.common.token.TokenSolver;
+import io.github.nnkwrik.common.token.injection.JWT;
+import io.github.nnkwrik.goodsservice.client.UserClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author nnkwrik
+ * @date 18/11/23 22:24
+ */
+@RestController
+public class TestController {
+
+    @Autowired
+    private UserClient client;
+
+    @GetMapping("/testFeign")
+    public Response testFeign() {
+        Map<String, String> map = new HashMap<>();
+        map.put("openId", "1");
+        return client.getSimpleUser(map);
+    }
+
+    @GetMapping("/testFeign2")
+    public Response testFeign2() {
+        List<String> ids = new ArrayList<>();
+        ids.add("1");
+        ids.add("3");
+        return client.getSimpleUserList(ids);
+    }
+
+    @GetMapping("/testFeign3")
+    public Response testFeign3() {
+        return client.getSimpleUser("1");
+    }
+
+
+    @GetMapping("/testInjection")
+    public JWTUser testInject(@JWT JWTUser jwt) {
+
+        System.out.println("============" + jwt);
+        return jwt;
+    }
+
+    @Autowired
+    private TokenSolver tokenSolver;
+
+    @GetMapping("/testJWTSolver")
+    public Object testJWTSolver() throws Exception {
+//        String token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJvcGVuSWQiOiIxIiwibmlja25hbWUiOiLmtYvor5XnlKjmiLciLCJhdmF0YXIiOiJodHRwczovL2F2YXRhcnMyLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzI5NjYyMTE0P3M9NDYwJnY9NCIsImV4cCI6MTU0MzExMDM1OX0.WnlQL2so0oHU7gUn-V0ij-uACizN7kQRBTwowZxwtvTMGw3_qE6ElJjzGUrRQDGZrad6eKxSf7m1v_ptz4UBoKbzickPGei-Qo9AkZZt0wL77HxislXkJltKHl3BgGbSdF2SkyARAPrlKyFy60aHEUw2dv6UbaDbJC_mUlBGwukyjOqCg5C4KNEgvnFiWYpHEQGKq3L12y1ba2VhtBDnrqAhKFjWvxiU5zM5ei5uDXaUhhUEvICJ1ariR9ZiLIbUcJ_CP63bVF3-yglTeCmZVmoddE0Cqq5d0nTDq3VozkIi74rFiK4oSK3wF8D_r9MeAzK1X-BUkkTkg-qV0_Vgjw";
+        String token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJvcGVuSWQiOiIxIiwibmlja25hbWUiOiLmtYvor5XnlKjmiLciLCJhdmF0YXIiOiJodHRwczovL2F2YXRhcnMyLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzI5NjYyMTE0P3M9NDYwJnY9NCIsImV4cCI6MTU0MzExMTg1MX0.Vf27ms7mRHOg8ptM0NTvgj5umfKae4Hk1lFuUmMjA4gdNLuhlqObp24JDsGfc4jo9yBKbwEdQ7DYOeKrFLybEArNXKZW2qf4XVUKIp2uLTlCw5n8BMSh13gPECjgfUInrMhEFPEB3IiJEhPDhQdiiRSYV4bQcCIS4d31OodqBTXDG0PC-FHc_7tgg3Xm7_ACLgI8JKOXmaSYPBrwGpQpu12-xXgR5DzjGR-TBICH8cY8SfkRexN6WriAYoGqJYFPKkkcnwKS4R6NzD_LGmHsCJ_XQjX5iWCtVz8SSL9tYS6E66NJDRFMWNkvDuwpuR9nefxv_zeqMJOcm6FVEYGZEw";
+        JWTUser solve = tokenSolver.solve(token);
+        System.out.println(solve);
+        return solve;
+    }
+}