登录认证
JWT令牌
令牌是一段字符串
- 承载业务数据,减少后续请求查询数据库的次数
- 防篡改,保证信息的合法性和有效性
- 全称 JSON Web Token(https://jwt.io/)
- 定义了一种简洁的、自包含的格式、用于通信双方以
json
格式安全
的传输信息。 - 组成
- 第一部分:Header,记录令牌类型、签名算法等。
- 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息。
- 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定密钥,通过与指定签名算法而来。
- 通过Base64进行编码
JWT相关依赖
1 2 3 4 5
| <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.4.0</version> </dependency>
|
JWT令牌的生成
1 2 3 4 5 6 7 8 9 10 11 12
| void genToke(){ Map<String,Object> claims = new HashMap<>(); claims.put("id",1); claims.put("username","zhangsan"); String Token = JWT.create() .withClaim("user", claims) .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)) .sign(Algorithm.HMAC256("密钥")); System.out.println(Token); }
|
JWT令牌验证
1 2 3 4 5 6 7 8 9 10
| @Test void parseToken(){ String token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"+ ".eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6InpoYW5nc2FuIn0sImV4cCI6MTcxOTUzNDgyNn0"+ ".RPFa6dpp3hYTAqsiBUnwkITSn9XWNBAnFhYacuuJBbw"; JWTVerifier jwtverifier = JWT.require(Algorithm.HMAC256("密钥")).build(); DecodedJWT decodedJWT = jwtverifier.verify(token); Map<String, Claim> claimMap = decodedJWT.getClaims(); System.out.println(claimMap.get("user")); }
|
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
| import com.auth0.jwt.JWT; import com. auth0.jwt.algorithms.Algorithm; import java.util.Date; import java.util.Map; public class JwtUtil { private static final String KEY = "lingzxl"; public static String genToken(Map<String, Object> claims) { return JWT.create() .withClaim("claims", claims) .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)) .sign(Algorithm.HMAC256(KEY)); } public static Map<String, Object> parseToken(String token) { return JWT.require(Algorithm.HMAC256(KEY)) .build() .verify(token) .getClaim("claims") .asMap(); } }
|
前置拦截器Token验证
- 创建
interceptors
包 - 创建
LoginInterceptor
类并实现HandlerInterceptor
- 重写
preHandle
方法 >参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); try{ Map<String, Object> claims = JwtUtil.parseToken(token); } catch (Exception e){ response.setStatus(401); return false; } return true; } }
|
- 注册拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration public class WebConfig implements WebMvcConfigurer { private LoginInterceptor loginInterceptor; @Autowired public void setLoginInterceptor(LoginInterceptor loginInterceptor){ this.loginInterceptor=loginInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register"); } }
|
使得返回json数据是不传出password参数
1 2
| @JsonIgnore private String password;
|
ThreadLocal
提供线程局部变量
- 用于存取数据:set()/get()
- 使用Threadloacl存储的数据,
线程安全
- 用完记得调用remove方法释放
使用原因
使得解析Token之类的操作只进行一次,减少计算资源的消耗。
工具代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class ThreadLocalUtil { private static final ThreadLocal THREAD_LOCAL = new ThreadLocal(); public static <T> T get(){ return (T) THREAD_LOCAL.get(); } public static void set(Object value){ THREAD_LOCAL.set(value); } public static void remove(){ THREAD_LOCAL.remove(); } }
|
后置拦截器
- 用于清除tomcat服务完一个请求后本地线程里的变量,防止内存泄漏
1 2 3 4 5 6
| @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { ThreadLocalUtil.remove(); }
|
更新用户基本信息
- 使用
@PutMapping("/update")
接收 - 在接受参数处写上
@RequestBody
用于把前端传入的json数据转换成User对象类