JWT主要用于保证前后端交互的安全,在服务器记录这个用户的信息(内存),前端每次请求后端都需要带上这个token数据(cookie或者localStorage等客户端缓存工具)。
然后拦截器,拦截、验证。
它有个弊端,就是无法删除。在注销用户时需要用额外的方法进行删除、比如各种花里胡哨的逻辑删除、使用时存redis或者数据库,然后进行删除。
依赖依赖
<!--引入jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
1、工具类
package com.tangxz.jwtsso.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.Map;
/**
* @author: 唐小尊
* @email: 1171702529@qq.com
* @cate: 2021/07/09 08:44
*/
public class JWTUtil {
private static final String SING = "1Q2w3e4r5t$@!#!@e";
/**
* 生成token
*
* @param map
* @return
*/
public static String getToken(Map<String, String> map) {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE, 7);//7天过期
//创建JWT builfer
JWTCreator.Builder builder = JWT.create();
//payload
map.forEach((k, v) -> {
builder.withClaim(k, v);
});
String token = builder.withExpiresAt(instance.getTime())//指定令牌过期时间
.sign(Algorithm.HMAC256(SING));
return token;
}
/**
* 验证token
* 过期、无该token,会报异常
*
* @param token
*/
public static void verifyToken(String token) {
JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
/**
* 获取token信息
*
* @param token
*/
public static DecodedJWT getTokenInfo(String token) {
return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
}
2、拦截器
package com.tangxz.jwtsso.interceptors;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tangxz.jwtsso.utils.JWTUtil;
import com.tangxz.jwtsso.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Objects;
/**
* @author: 唐小尊
* @email: 1171702529@qq.com
* @cate: 2021/07/09 14:43
*/
@Slf4j
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
log.info("当前token为:[{}]",token);
R r = R.ok().put("msg","token有效");
try {
JWTUtil.verifyToken(token);
}catch (SignatureVerificationException e){
e.printStackTrace();
log.error("无效签名!");
r = R.error().put("msg","无效签名");
}catch (TokenExpiredException e){
e.printStackTrace();
log.error("token过期!");
r = R.error().put("msg","token过期");
}catch (AlgorithmMismatchException e){
e.printStackTrace();
log.error("token算法不一致!");
r = R.error().put("msg","token算法不一致");
}catch (Exception e){
e.printStackTrace();
log.error("token无效!");
r = R.error().put("msg","token无效");
}
if (!r.getCode().equals(0)){
//用response发送给前端
String json = new ObjectMapper().writeValueAsString(r);
log.info(json);
response.setContentType("application/json;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.print(json);
//返回false,即不进行之后的操作
return false;
}
return true;
}
}
3、使用拦截器
package com.tangxz.jwtsso.config;
import com.tangxz.jwtsso.interceptors.JWTInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author: 唐小尊
* @email: 1171702529@qq.com
* @cate: 2021/07/09 14:51
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/user/test")//拦截
.excludePathPatterns("/user/login");//放行
}
}
4、controller层,用户取出需要的数据
package com.tangxz.jwtsso.modules.user.controller;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tangxz.jwtsso.modules.user.entity.User;
import com.tangxz.jwtsso.modules.user.service.IUserService;
import com.tangxz.jwtsso.utils.JWTUtil;
import com.tangxz.jwtsso.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: User
* @Author: tangxz
* @Userte: 2020-07-09
* @Version: V1.0
*/
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
@PostMapping("/login")
public R login(String name, String password){
User user = userService.getOne(new QueryWrapper<User>().eq("name",name).eq("password",password).last("limit 1"));
if (user!=null){
Map<String,String> map = new HashMap<>();
map.put("id", String.valueOf(user.getId()));
map.put("name", user.getName());
String token = JWTUtil.getToken(map);
return R.ok().put("token",token);
}
return R.error().put("msg","登陆失败");
}
//如果要用到token信息,则直接参数HttpServletRequest,getHeader("token");
@PostMapping("/test")
public R test(HttpServletRequest request){
String token = request.getHeader("token");
DecodedJWT tokenInfo = JWTUtil.getTokenInfo(token);
String id = tokenInfo.getClaim("id").asString();
String name = tokenInfo.getClaim("name").asString();
log.info("用户id为{}",id);
log.info("用户名为{}",name);
return R.ok().put("name",name).put("id",id);
}
}