JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的拗小、自包含的方式绊袋,用于作為JSON對象在各方之間安全地傳輸信息。該信息可以被驗證和信任翁潘,因為它是數(shù)字簽名的。
web項目使用jwt的優(yōu)點
1.token 是分布式的由 用戶保存歼争,后端只做校驗
2.jwt可以保存 用戶id 等有效信息拜马。減少查詢數(shù)據(jù)庫操作。
3.有過期時間沐绒,安全俩莽、可靠。
實現(xiàn)方法
這里我們通過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.代碼中添加配置對應(yīng)的 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方法調(diào)用之前
// 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());
//添加構(gòu)成JWT的參數(shù)
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/