使用分布式时,就需要JWT与SpringSecurity一起进行配合使用。
Jwt工具类
package com.bep.server.config.jwt;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
public static final String CLIAM_KEY_USERNAME = "sub";
public static final String CLIAM_KEY_CREATED = "created";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String generateToken(UserDetails userDetails){
Map claims = new HashMap();
claims.put(CLIAM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLIAM_KEY_CREATED, new Date());
return generateToken(claims);
}
private String generateToken(Map claims){
return Jwts.builder()
.setClaims(claims) // 荷载
.setExpiration(generateExpiration()) // 失效时间
.signWith(SignatureAlgorithm.HS256, secret) // 生成签名
.compact(); // 拼接
}
private Date generateExpiration() {
return new Date(System.currentTimeMillis() + expiration);
}
public String getUsernameFromToken(String token){
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
e.printStackTrace();
}
return username;
}
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
e.printStackTrace();
}
return claims;
}
}
上一期,演示了认证的过程,所以认证是到了方法中。实际上在方法之前就需要完成认证。即在Security的过滤器中完成认证。自定义认证过滤器,把过滤器加到Security过滤器中。
jwt过滤器
package com.bep.server.config.jwt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtFilter extends oncePerRequestFilter {
@Value("${jwt.tokenHead}")
private String tokenHead;
// private String tokenHead = "Bearer";
@Value("${jwt.tokenHeader}")
private String tokenHeader;
// private String tokenHeader = "Authorization";
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader(tokenHeader);
System.out.println(authHeader);
if(authHeader != null && authHeader.startsWith(tokenHead)){
//获取Token
String authToken = authHeader.substring(tokenHead.length());
//从Token中获取用户名
String username = jwtUtil.getUserNameFromToken(authToken);
//用户未登录
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
//进行登录
UserDetails admin = userDetailsService.loadUserByUsername(username);
//判断Token是否合法
if(jwtUtil.validateToken(authToken,admin)){
//用户登录成功, 把用户信息加入到SecurityContextHolder中
UsernamePasswordAuthenticationToken authenticationToken = new
UsernamePasswordAuthenticationToken(admin,null, admin.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}else{
System.out.println("登录失败");
}
}
}
filterChain.doFilter(request,response);
}
}
把Jwt过滤器加到Security过滤器中
@Override
protected void configure(HttpSecurity http) throws Exception {
//添加jwt登录授权过滤器
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
没登录之前,没有访问/test1的权限
进行登录
访问/test1是把token加入到header中
最终完成用户权限认证



