JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
web项目使用jwt的优点
1.token 是分布式的由 用户保存,后端只做校验
2.jwt可以保存 用户id 等有效信息。减少查询数据库操作。
3.有过期时间,安全、可靠。
实现方法
这里我们通过spring 的拦截器 + jwt 完成对token的校验
通过注册的jwt拦截器,拦截web请求,验证jwt是否有效
1. pom.xml 中添加依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
2. yml 配置文件中 添加如下配置
jwt:
header: Authorization
base64Secret: your-base-64-secret # your-base-64-secret
issuer: your-app-server
expiresSecond: 17280000
3.代码中添加配置对应的 config 文件
/**
* @author river
* @create 2018/4/4 下午2:52
*/
@Component
@ConfigurationProperties(prefix = "jwt")
@Data
public class JwtConfig {
private String base64Secret;
private String issuer;
private Long expiresSecond;
private String header;
}
4. 添加jwt拦截器
/**
* @author river
* @create 2018/4/4 上午10:00
* @desc 用户的签名,jwt的解析放在这里
*/
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtConfig jwtConfig;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//controller方法调用之前
// get jwt token from header - > Authorization
String jwtToken = httpServletRequest.getHeader(jwtConfig.getHeader());
//parse jwt , get payload
Claims claims = JwtUtil.parseJWT(jwtToken,jwtConfig.getBase64Secret());
log.info("拦截器 -> jwt jwtToken = {} , claims = {} ",jwtToken, JSONObject.toJSON(claims));
//用户未登陆
// ValidatedUtil.notNull(claims, MsgConstantEnum.NOT_LOGIN);
Integer userId = (Integer) claims.get("userId");
// ValidatedUtil.notNull(userId,"用户id不能为null");
//ValidatedUtil.notNull(account,"账号不能为null");
return true;
}
}
5. 注册拦截器
/**
* @author river
* @create 2018/4/4 上午9:58
*/
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
@Resource
private JwtInterceptor jwtInterceptor;
/**
* 添加拦截器
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor).addPathPatterns("/**")
.excludePathPatterns("/onLogin", "/onRegist");
super.addInterceptors(registry);
}
}
提供一个jwt的工具类
@Slf4j
public class JwtUtil {
public static Claims parseJWT(String jsonWebToken, String base64Security){
try {
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
.parseClaimsJws(jsonWebToken).getBody();
return claims;
}catch(Exception e) {
log.error("验证token错误");
return null;
}
}
public static String createJWT(int userId, String account, String issuer, long TTLMillis, String base64Security) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//生成签名密钥
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.claim("userId", userId)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey);
//添加Token过期时间
if (TTLMillis >= 0) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
long expMillis = nowMillis + TTLMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
//生成JWT
return builder.compact();
}
}
参考地址
https://jwt.io/