一、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注解的方式
@Beanpublic 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值
@Overridepublic 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 {@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic 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;}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//清空ThreadLocal中的数据ThreadLocalUtil.remove();}
}