SpringBoot-JWT+Security权限认证框架
JWT
jwt说白了就是一个字符串生成器+检查器,只不过加密了。
token是一个加密的用户身份钥匙字符串,用户登录时获取它,用户请求时拿着它进行访问。
token在登录后生成,并返回给客户端,客户端将一直持有它。当客户端进行请求时将token携带,过滤器拦截登录未放行的请求,检查他们是否携带合法token,合法则通过,不合法则拦截。
验证token时jwt可通过token获取里面的信息,并和进行检查,检查token合法即允许通过。(token字符串是加密的串,只要它是合法的就直接允许,因此不用再比对用户密码)
token本身是一个通过base64URL编码加密的字符串:
格式如下:
aaaaaaaaa.bbbbbbbbbbbb.cccccccccccc
令牌由3个部分组成,每个部分都被base64URL加密:
- Header:头,token的类型、及使用的算法
- Payload:有效载荷,你添加的信息
- Signature:签名
密码等信息请不要放进来,容易被解密。
jwt中token在加密前其实就是json文本。
1.创建token
一个token中一般存放用户信息(用户名、权限)、签发时间、过期时间、私钥即可,在创建时指定算法。
private long key="jjlahjdahglsnaafafasfafwlalahnf";//私钥(尽量长)
private long times=100000; //有效时长
/**
* 创建token
* @param claims 用户信息map
* @return token字符串
*/
public String createToken(Map<String, Object> claims) {
return "Bearer "+Jwts.builder() //Bearer token
.claim("auth", claims)//claims:存放用户信息(key:auth)
.setId(UUID.randomUUID().toString())//令牌随机ID
.setIssuedAt(new Date()) //令牌签发时间
.setExpiration(new Date((new Date()).getTime() +times))//令牌过期时间
.compressWith(CompressionCodecs.DEFLATE)
.signWith(key, SignatureAlgorithm.HS512) //加密算法
.compact();
}
2.其他操作
由于操作根据你的业务需求来,所以只列举几个功能
//获取存储信息部分
Claims claims = Jwts.parser().setSigningKey(私钥key).parseClaimsJws(token).getBody();
//验证token中私钥,抛异常则错误
Jwts.parser().setSigningKey(私钥key).parseClaimsJws(token);
//获取权限列表
Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
//获取用户账号信息
Map<String,Object> map = (Map<String, Object>) claims.get(AUTHORITIES_KEY);
//获取过期时间
Date expiration = claims.getExpiration();
3.过滤器认证示例
请求时获取完token,你想验证哪些方面就判断哪些方面即可,下面的仅供参考。
/**
* Description 实现token验证的过滤器
*/
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = null;
//获取请求时携带的token全串,Authorization为请求时token的key值
String bearerToken = request.getHeader("Authorization");
//请求全token为字符串 且 前缀正确
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
//获取jwt令牌串(不带附加串token)
token = bearerToken.substring("Bearer ".length());
}
//下面的jwtTokenUtils是自己写的工具类,参考1、2节创建
//token为字符串 且 私钥正确
if (StringUtils.hasText(token) && jwtTokenUtils.validateToken(token)) {
Authentication authentication = jwtTokenUtils.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
log.debug("set Authentication to security context for '{}', uri: {}", authentication.getName(), requestRri);
} else {
log.debug("no valid JWT token found, uri: {}", requestRri);
}
/*
* 通知 Web 容器把请求交给 Filter 链中的下一个 Filter 去处理,
* 如果当前调用此方法的 Filter 对象是Filter 链中的最后一个 Filter,
* 那么将把请求交给目标 Servlet 程序去处理。
*/
filterChain.doFilter(request, response);
}
}
4.springboot中的依赖
可能是版本原因,私钥得设置超长,否则会报错
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.6</version>
</dependency>