一、JWT理论部分
1.JWT概述
JWT(JSON Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以 JSON 对象的形式安全地传输信息。这种信息可以被验证和信任,因为它是数字签名的。JWT通常用于身份验证和授权,可以在浏览器和服务器之间传输,也可以在不同的系统之间传输。
JWT通常由三部分组成:
头部(Header):一个JSON对象,描述了令牌的元数据,例如令牌的算法和类型。
有效载荷(Payload):一个JSON对象,包含了令牌的声明,例如用户信息、发行人、过期时间等。
签名(Signature):使用头部中指定的算法,对头部和有效载荷的Base64编码字符串进行加密,生成签名。
2.在通用模块下
导入jwt依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
3.编写JWT的工具类:
signKey:密钥
expire:有效时长
最好使用@ConfigurationProperties,在所需要模块的application.yml中进行设置signKey和expire
public class JwtUtils {
private static String signKey = "signKey";
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
4.JWT工具类(加入容器)
方式一:
在使用的类中,通过@Bean注解的方式
@Bean
public JwtUtils jwtUtils(){
return new JwtUtils();
}
方式二:
当你在 Spring Boot 应用程序中使用 @EnableAutoConfiguration
注解时,Spring Boot 会读取 META-INF/spring.factories
文件中定义的自动配置类。
在resource中创建文件夹META-INF,然后在其创建spring.factories文件
添加 单个
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.etc.company.common.utils.JwtUtils
例如添加多个就使用(逗号和斜杠)进行分隔
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.etc.common.config.RedisConfig,\
com.etc.common.config.MyBatisConfig,\
com.etc.company.common.utils.JwtUtils
二、JWT实战
登录时,如果登录成功则获取返回的token值
@Override
public String loginUserByPassword(LoginDTO loginDTO) {
User user = getUserByPhone(loginDTO.getPhone());
if(Md5Util.checkPassword(loginDTO.getPhone()+loginDTO.getPassword(),user.getPassword())){
Map<String, Object> claims = new HashMap<>();
claims.put("id",user.getId());
claims.put("phone",user.getPhone());
String token = JwtUtils.generateJwt(claims);
redisTemplate.opsForValue().set(token,token,2,TimeUnit.HOURS);
return token;
}
return null;
}
在拦截器中进行token校验:
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
try{
String redisToken = (String) redisTemplate.opsForValue().get(token);
if (redisToken == null){
throw new ForbiddenException("token失效");
}
Claims claims = JwtUtils.parseJWT(token);
//把业务数据存储到ThreadLocal中
ThreadLocalUtil.set(claims);
return true;
}catch (Exception e){
response.setStatus(401);
return false;
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//清空ThreadLocal中的数据
ThreadLocalUtil.remove();
}
}