Java自定义注解(三)
前面介绍了如何获取注解的值,那么本篇将介绍如何真正的在实际的业务中去使用()自定义注解,并且结合JWT组件来实现用户信息的通过注解的方式来获取
JWT工具类
package com.example.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.util.DigestUtils;
import java.util.Date;
import java.util.HashMap;
public class JwtUtils {
//需要的过期时间
public final static long EXPIRE_TIME = 60 * 1000;
//需要的生成密钥,防止token伪造
public final static String TOKEN_SECRET = "5d41402abc4b2a76b9719d911017c592";
/**
* 根据用户id生成token
*
* @param id 用户id
* @return
*/
public static String generateToken(String id) {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//使用hash算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
HashMap<String, Object> header = new HashMap<>();
header.put("type", "JWT");
header.put("alg", "HMAC256");
String token = JWT.create().withHeader(header).withExpiresAt(date).withClaim("id", id).sign(algorithm);
return token;
}
/**
* 验证token是否是服务器颁发的
*
* @param token 用户传过来的token参数
* @return
*/
public static boolean verifyToken(String token) {
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier build = JWT.require(algorithm).build();
build.verify(token);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 从token中取出负载,即JWT create的时候加入的claim
*
* @param token
* @return
*/
public static String getClaim(String token) {
DecodedJWT decode = JWT.decode(token);
Claim id = decode.getClaim("id");
return id.asString();
}
public static void main(String[] args) {
//生成一个token
System.out.println(generateTokenSecret());
//根据用户id生成一个token
String token = generateToken("10");
//校验token
verifyToken(token);
//获取token中的负载,也就是当时传入进去的值
System.out.println(getClaim(token));
}
/**
* 用md5生成一个密钥
*
* @return
*/
public static String generateTokenSecret() {
return DigestUtils.md5DigestAsHex("hello".getBytes());
}
}
自定义注解
package com.example.annotaion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserId {
}
使用HandlerMethodArgumentResolver
在resolver里面来处理校验token逻辑,同时根据用户传参数信息,通过自己到校验逻辑,封装用户信息到自定义注解里面的参数里
package com.example.resolver;
import com.example.annotaion.UserId;
import com.example.util.JwtUtils;
import org.springframework.core.MethodParameter;
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;
public class UserIdHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(String.class)
&& parameter.hasParameterAnnotation(UserId.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String token = webRequest.getParameter("token");
boolean b = JwtUtils.verifyToken(token);
if (b) {
return JwtUtils.getClaim(token);
}
return null;
}
}
注册参数解析器
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 {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
// resolvers.add(new UserInfoArgumentResolver());
resolvers.add(new UserIdHandlerMethodArgumentResolver());
}
}
controller里面的使用
package com.example.controller;
import com.example.annotaion.CacheResult;
import com.example.annotaion.KeyVerify;
import com.example.annotaion.LoginUserInfo;
import com.example.annotaion.UserId;
import com.example.entity.LoginUser;
import com.example.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@CacheResult(key = "class_key", cacheName = "class_cacheName")
@Slf4j
public class TestController {
/**
* 模拟用户登录,登录成功后返回给用户一个token
* @param userid
* @return
*/
@RequestMapping("/login")
public Map select(@UserId String userid) {
HashMap<String, Object> map = new HashMap<>();
log.info("用户认证通过,id是:{}", userid);
map.put("code", 200);
String oid = "10";
map.put("token", JwtUtils.generateToken(oid));
return map;
}
/**
* 用户拿着token来付款,此时参数中没有用户的id信息,但是可以通过解析器里面的token来获取
* @param id
* @param token
*/
@RequestMapping("pay")
public String pay(@UserId String id, String token) {
log.info("id:{}", id);
return id;
}
}
login方法模拟用户登录,用户登录成功之后,返回一个token给用户,当用户下次访问付款接口当时候,传统的从session中获取用户信息的伪代码如下
@RequestMapping("/pay2")
public void pay(HttpServletRequest request) {
HttpSession session = request.getSession();
User user = (User)session.getAttribute("user-info");
String token = request.getParameter("token");
boolean b = JwtUtils.verifyToken(token);
if (b){
String id = JwtUtils.getClaim(token);
log.info("id:{}", id);
}
}
但是通过使用解析器以及自定义注解,我们成功得将校验逻辑和业务分离了,整个controller里面变得清洁了
请求测试
登录服务器
http://localhost:8080/login
付款请求
http://localhost:8080/pay?token=eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYiLCJ0eXAiOiJKV1QifQ.eyJpZCI6IjEwIiwiZXhwIjoxNjE0ODQ2MTExfQ.CA6ehO1Z13sQZ3TE_QYJCnxUKg2xffKcSNOprNZaL8s
控制台输出
2021-03-04 16:20:51.216 INFO 15612 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-03-04 16:20:51.216 INFO 15612 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-03-04 16:20:51.220 INFO 15612 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
2021-03-04 16:20:51.243 INFO 15612 --- [nio-8080-exec-1] com.example.controller.TestController : 用户认证通过,id是:null
2021-03-04 16:21:05.735 INFO 15612 --- [nio-8080-exec-2] com.example.controller.TestController : id:10
还没有评论,来说两句吧...