Java自定义注解(三)

忘是亡心i 2022-11-05 08:31 154阅读 0赞

前面介绍了如何获取注解的值,那么本篇将介绍如何真正的在实际的业务中去使用()自定义注解,并且结合JWT组件来实现用户信息的通过注解的方式来获取

JWT工具类

  1. package com.example.util;
  2. import com.auth0.jwt.JWT;
  3. import com.auth0.jwt.JWTVerifier;
  4. import com.auth0.jwt.algorithms.Algorithm;
  5. import com.auth0.jwt.interfaces.Claim;
  6. import com.auth0.jwt.interfaces.DecodedJWT;
  7. import org.springframework.util.DigestUtils;
  8. import java.util.Date;
  9. import java.util.HashMap;
  10. public class JwtUtils {
  11. //需要的过期时间
  12. public final static long EXPIRE_TIME = 60 * 1000;
  13. //需要的生成密钥,防止token伪造
  14. public final static String TOKEN_SECRET = "5d41402abc4b2a76b9719d911017c592";
  15. /**
  16. * 根据用户id生成token
  17. *
  18. * @param id 用户id
  19. * @return
  20. */
  21. public static String generateToken(String id) {
  22. Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
  23. //使用hash算法
  24. Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
  25. HashMap<String, Object> header = new HashMap<>();
  26. header.put("type", "JWT");
  27. header.put("alg", "HMAC256");
  28. String token = JWT.create().withHeader(header).withExpiresAt(date).withClaim("id", id).sign(algorithm);
  29. return token;
  30. }
  31. /**
  32. * 验证token是否是服务器颁发的
  33. *
  34. * @param token 用户传过来的token参数
  35. * @return
  36. */
  37. public static boolean verifyToken(String token) {
  38. try {
  39. Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
  40. JWTVerifier build = JWT.require(algorithm).build();
  41. build.verify(token);
  42. return true;
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. }
  46. return false;
  47. }
  48. /**
  49. * 从token中取出负载,即JWT create的时候加入的claim
  50. *
  51. * @param token
  52. * @return
  53. */
  54. public static String getClaim(String token) {
  55. DecodedJWT decode = JWT.decode(token);
  56. Claim id = decode.getClaim("id");
  57. return id.asString();
  58. }
  59. public static void main(String[] args) {
  60. //生成一个token
  61. System.out.println(generateTokenSecret());
  62. //根据用户id生成一个token
  63. String token = generateToken("10");
  64. //校验token
  65. verifyToken(token);
  66. //获取token中的负载,也就是当时传入进去的值
  67. System.out.println(getClaim(token));
  68. }
  69. /**
  70. * 用md5生成一个密钥
  71. *
  72. * @return
  73. */
  74. public static String generateTokenSecret() {
  75. return DigestUtils.md5DigestAsHex("hello".getBytes());
  76. }
  77. }

自定义注解

  1. package com.example.annotaion;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Target(ElementType.PARAMETER)
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface UserId {
  9. }

使用HandlerMethodArgumentResolver

在resolver里面来处理校验token逻辑,同时根据用户传参数信息,通过自己到校验逻辑,封装用户信息到自定义注解里面的参数里

  1. package com.example.resolver;
  2. import com.example.annotaion.UserId;
  3. import com.example.util.JwtUtils;
  4. import org.springframework.core.MethodParameter;
  5. import org.springframework.web.bind.support.WebDataBinderFactory;
  6. import org.springframework.web.context.request.NativeWebRequest;
  7. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  8. import org.springframework.web.method.support.ModelAndViewContainer;
  9. public class UserIdHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
  10. @Override
  11. public boolean supportsParameter(MethodParameter parameter) {
  12. return parameter.getParameterType().isAssignableFrom(String.class)
  13. && parameter.hasParameterAnnotation(UserId.class);
  14. }
  15. @Override
  16. public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
  17. String token = webRequest.getParameter("token");
  18. boolean b = JwtUtils.verifyToken(token);
  19. if (b) {
  20. return JwtUtils.getClaim(token);
  21. }
  22. return null;
  23. }
  24. }

注册参数解析器

import com.example.interceptor.AuthenticationInterceptor;
import com.example.resolver.UserIdHandlerMethodArgumentResolver;
import com.example.resolver.UserInfoArgumentResolver;
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.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

//配置拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

  1. @Override
  2. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {

// resolvers.add(new UserInfoArgumentResolver());
resolvers.add(new UserIdHandlerMethodArgumentResolver());
}

}

controller里面的使用

  1. package com.example.controller;
  2. import com.example.annotaion.CacheResult;
  3. import com.example.annotaion.KeyVerify;
  4. import com.example.annotaion.LoginUserInfo;
  5. import com.example.annotaion.UserId;
  6. import com.example.entity.LoginUser;
  7. import com.example.util.JwtUtils;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RestController;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. @RestController
  14. @CacheResult(key = "class_key", cacheName = "class_cacheName")
  15. @Slf4j
  16. public class TestController {
  17. /**
  18. * 模拟用户登录,登录成功后返回给用户一个token
  19. * @param userid
  20. * @return
  21. */
  22. @RequestMapping("/login")
  23. public Map select(@UserId String userid) {
  24. HashMap<String, Object> map = new HashMap<>();
  25. log.info("用户认证通过,id是:{}", userid);
  26. map.put("code", 200);
  27. String oid = "10";
  28. map.put("token", JwtUtils.generateToken(oid));
  29. return map;
  30. }
  31. /**
  32. * 用户拿着token来付款,此时参数中没有用户的id信息,但是可以通过解析器里面的token来获取
  33. * @param id
  34. * @param token
  35. */
  36. @RequestMapping("pay")
  37. public String pay(@UserId String id, String token) {
  38. log.info("id:{}", id);
  39. return id;
  40. }
  41. }

login方法模拟用户登录,用户登录成功之后,返回一个token给用户,当用户下次访问付款接口当时候,传统的从session中获取用户信息的伪代码如下

  1. @RequestMapping("/pay2")
  2. public void pay(HttpServletRequest request) {
  3. HttpSession session = request.getSession();
  4. User user = (User)session.getAttribute("user-info");
  5. String token = request.getParameter("token");
  6. boolean b = JwtUtils.verifyToken(token);
  7. if (b){
  8. String id = JwtUtils.getClaim(token);
  9. log.info("id:{}", id);
  10. }
  11. }

但是通过使用解析器以及自定义注解,我们成功得将校验逻辑和业务分离了,整个controller里面变得清洁了

请求测试

登录服务器

http://localhost:8080/login
image.png

付款请求

http://localhost:8080/pay?token=eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYiLCJ0eXAiOiJKV1QifQ.eyJpZCI6IjEwIiwiZXhwIjoxNjE0ODQ2MTExfQ.CA6ehO1Z13sQZ3TE_QYJCnxUKg2xffKcSNOprNZaL8s
image.png

控制台输出

  1. 2021-03-04 16:20:51.216 INFO 15612 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
  2. 2021-03-04 16:20:51.216 INFO 15612 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
  3. 2021-03-04 16:20:51.220 INFO 15612 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
  4. 2021-03-04 16:20:51.243 INFO 15612 --- [nio-8080-exec-1] com.example.controller.TestController : 用户认证通过,id是:null
  5. 2021-03-04 16:21:05.735 INFO 15612 --- [nio-8080-exec-2] com.example.controller.TestController : id:10

发表评论

表情:
评论列表 (有 0 条评论,154人围观)

还没有评论,来说两句吧...

相关阅读