前言
简单了解一下原理,重点知道怎么用
Token:简单来说就是一个用户在一段时间内的标识,只有登录成功才能获得Token,一般情况下只有携带Token的请求才能被Interceptor放行。
Interceptor:这是一个过滤器技术,可以将Interceptor理解为一个筛子,在请求到达控制层前进行拦截,根据具体的业务需求,可以对请求进行一定操作,比如拦截、放行等等。
Jwt快速入门
JwtToken的组成
标头,一般用来标识令牌类型和所使用的签名算法。
1 2 3 4
| { "alg": "HS256", "typ": "JWT" }
|
有效载荷,保存自定义信息。
1 2 3 4 5 6
| { "sub": "1234567890", "name": "John Doe", "admin": true, "iat": 1516239022 }
|
签名,融合了Header和Payload,根据输入的secret基于签名算法生成而来,是保证token不被篡改。
上面的信息都是json格式的字符串,标头和载荷部分是Base64编码后直接构成token的前两部分,第三部分由标签算法、密钥和输入的信息(Header、Payload)决定。
Token的创建与验证
使用jwt提供的工具包快速生成令牌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Test public void jwtCreate(){ Map<String, Object> claims = new HashMap<>(); claims.put("username", "m1kasaz"); claims.put("id", 1); String token = Jwts.builder() .addClaims(claims) .signWith(SignatureAlgorithm.HS256, "bTFrYXNheg==") .setExpiration(new Date(System.currentTimeMillis()+3600*60)) .compact(); System.out.println(token); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void jwtParse(){ String token = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJtMWthc2F6IiwiZXhwIjoxNzUxMzgyMDQ0fQ.vuyp1XEZv3ncI-F6U63QlRHymG_du_IlETE0ZiVarfE"; Claims claims = Jwts.parser() .setSigningKey("bTFrYXNheg==") .parseClaimsJws(token) .getBody(); System.out.println(claims); }
|
一般将jwt创建和验证封装为工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class jwtUtils { private static final String Key = "bTFrYXNheg=="; private static final Long EXP = 3600*60L; private static final SignatureAlgorithm SIGN = SignatureAlgorithm.HS256; public String createToken(Map<String, Object> claims){ String token = Jwts.builder() .setClaims(claims) .setExpiration(new Date(System.currentTimeMillis()+EXP)) .signWith(SIGN, Key) .compact(); return token; }
public Claims parseToken(String token){ Claims claims = Jwts.parser() .setSigningKey(Key) .parseClaimsJws(token) .getBody(); return claims; } }
|
Interceptor快速入门
Interceptor由springboot提供,基于AOP(面向切面编程)思想的过滤技术。
自定义Interceptor
想要自定义 Interceptor,必须实现HandlerInterceptor或HandlerInterceptorAdapter类中的一个。并需要重写三个方法中至少一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return HandlerInterceptor.super.preHandle(request, response, handler); }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); }
|
下面是一个用于控制登录请求的过滤器示例
主要实现的功能是解析jwt令牌,如果令牌合法就放行,否则拒绝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @Component @Slf4j public class JwtTokenUserInterceptor implements HandlerInterceptor { @Autowired private JwtProperties jwtProperties;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; }
String token = request.getHeader(jwtProperties.getUserTokenName());
try { log.info("jwt校验:{}", token); Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token); Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString()); BaseContext.setCurrentId(userId); log.info("当前用户id:", userId); return true; } catch (Exception ex) { response.setStatus(401); return false; } } }
|
注册过滤器
ok,在知道怎样创建inteceptor过滤器后,我们怎么使用呢?
其实AOP将自动帮我们完成调用过程,我们只需要知道怎么注册一个inteceptor过滤器就好了。
注册过程可以借助Springboot的WebMvcConfigurer配置类,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Configuration @Slf4j public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
protected void addInterceptors(InterceptorRegistry registry) { log.info("开始注册自定义拦截器..."); registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns("/admin/**") .excludePathPatterns("/admin/employee/login"); }
|
jwt官方文档
csdn