String token = jwtBuilder.compact();
return token;
}
/**
• 生成Token令牌
•
• @param userDetails 用户
• @return 令牌Token
*/
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put(“sub”, userDetails.getUsername());
claims.put(“created”, new Date());
return generateToken(claims);
}
/**
• 从token中获取数据声明claim
•
• @param token 令牌token
• @return 数据声明claim
*/
public Claims getClaimsFromToken(String token) {
try {
SecretKey key = getSecretKey(secret);
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
return claims;
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
log.error(“token解析错误”, e);
throw new IllegalArgumentException(“Token invalided.”);
}
}
public String getUserRole(String token) {
return (String) getClaimsFromToken(token).get(“role”);
}
/**
• 从token中获取登录用户名
•
• @param token 令牌
• @return 用户名
*/
public String getSubjectFromToken(String token) {
String subject;
try {
Claims claims = getClaimsFromToken(token);
subject = claims.getSubject();
} catch (Exception e) {
subject = null;
}
return subject;
}
/**
• 获取token的过期时间
•
• @param token token
• @return 过期时间
*/
public Date getExpirationFromToken(String token) {
return getClaimsFromToken(token).getExpiration();
}
/**
• 判断token是否过期
•
• @param token 令牌
• @return 是否过期:已过期返回true,未过期返回false
*/
public Boolean isTokenExpired(String token) {
Date expiration = getExpirationFromToken(token);
return expiration.before(new Date());
}
/**
• 验证令牌:判断token是否非法
•
• @param token 令牌
• @param userDetails 用户
• @return 如果token未过期且合法,返回true,否则返回false
*/
public Boolean validateToken(String token, UserDetails userDetails) {
//如果已经过期返回false
if (isTokenExpired(token)) {
return false;
}
String usernameFromToken = getSubjectFromToken(token);
String username = userDetails.getUsername();
return username.equals(usernameFromToken);
}
}
• 测试代码
@SpringBootTest
public class JwtUtilTest {
@Resource
private JwtUtil jwtUtil;
@Resource
private PasswordEncoder passwordEncoder;
@Test
void fun() {
System.out.println(passwordEncoder);
SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
System.out.println(secretKey);
}
//生成token
@Test
void generateToken() {
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
}
@Test
void getClaimsFromToken() {
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
Claims claims = jwtUtil.getClaimsFromToken(token);
System.out.println(claims);
}
@Test
void getSubjectFromToken() {
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
String username = jwtUtil.getSubjectFromToken(token);
System.out.println(username);
}
@Test
void getExpirationFromToken() {
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
Date date = jwtUtil.getExpirationFromToken(token);
System.out.println(new SimpleDateFormat(“YYYY-MM-dd HH:mm:ss”).format(date));
}
@Test
void isTokenExpired() {
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
Boolean res = jwtUtil.isTokenExpired(token);
System.out.println(res);
}
@Test
void validateToken() {
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
User user2 = new User(“zhangsan”, “”, AuthorityUtils.createAuthorityList());
Boolean res = jwtUtil.validateToken(token, user2);
System.out.println(res);
}
//模拟篡改
@Test
void fake() {
// 将我改成你生成的token的第一段(以.为边界)
String encodedHeader = “eyJhbGciOiJIUzI1NiJ9”;
// 测试4: 解密Header
byte[] header = Base64.decodeBase64(encodedHeader.getBytes());
System.out.println(new String(header));
// 将我改成你生成的token的第二段(以.为边界)
String encodedPayload = “eyJpZCI6IjEiLCJpYXQiOjE1NjU1ODk1NDEsImV4cCI6MTU2Njc5OTE0MX0”;
// 测试5: 解密Payload
byte[] payload = Base64.decodeBase64(encodedPayload.getBytes());
System.out.println(new String(payload));
//用户信息
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
// 测试6: 这是一个被篡改的token,因此会报异常,说明JWT是安全的
jwtUtil.validateToken(“eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEiLCJpYXQiOjE1NjU1ODk3MzIsImV4cCI6MTU2Njc5OTMzMn0.nDv25ex7XuTlmXgNzGX46LqMZItVFyNHQpmL9UQf-aUx”, user);
}
}
2、创建没有权限时,Jwt拒绝访问的处理器
/**
• 当用户在没有授权的时候,返回的指定信息
*/
@Slf4j
@Component
public class jwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws ServletException {
log.info(“用户访问没有授权资源:{}”,e.getMessage());
response.setContentType(“application/json;charset=utf-8”);
response.setCharacterEncoding(“utf-8”);
try(PrintWriter out = response.getWriter()😉{
Result result = ResultUtil.fail(“用户访问未授权资源”).setCode(HttpServletResponse.SC_UNAUTHORIZED);
out.write(JsonUtil.obj2String(result));
out.flush();
}catch (IOException exception){
}
}
}
3、创建没有token时,Jwt的EntryPoint
/**
*用户访问资源没有携带正确的token,时返回的信息
*/
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws ServletException, IOException {
log.info(“用户访问资源没有携带正确的token:{}”,e.getMessage());
response.setContentType(“application/json;charset=utf-8”);
response.setCharacterEncoding(“utf-8”);
try(PrintWriter out = response.getWriter()😉{
Result result = ResultUtil.fail(“用户访问资源没有携带正确的token”).setCode(HttpServletResponse.SC_UNAUTHORIZED);
out.write(JsonUtil.obj2String(result));
out.flush();
}catch (IOException exception){
}
}
}
4、创建UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//直接写死数据信息,可以在这里获取数据库的信息并进行验证
//UserDetails user = User.withUsername(username)
// .password(passwordEncoder.encode(“1234”))
// .authorities(“Role_vip,user:list,user:update”)
// .build();
User user = new User(username, passwordEncoder.encode(“1234”),
AuthorityUtils.commaSeparatedStringToAuthorityList(“ROLE_vip,user:list,user:update”));
return user;
}
}
5、创建Jwt认证过滤器
@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Resource
private JwtUtil jwtUtil;
@Resource
private UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String token = request.getHeader(jwtUtil.getHeader());
log.info(“header token:{}”, token);
//如果请求头中有token,则进行解析,并且设置认证信息
if (token != null && token.trim().length() > 0) {
//根据token获取用户名
String username = jwtUtil.getSubjectFromToken(token);
// 验证username,如果验证合法则保存到SecurityContextHolder
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// JWT验证通过,使用Spring Security 管理
if (jwtUtil.validateToken(token, userDetails)) {
//加载用户、角色、权限信息
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
//如果请求头中没有Authorization信息则直接放行
chain.doFilter(request, response);
}
}
6、配置SpringSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityJwtConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Resource
private com.hc.jwt.jwtAccessDeniedHandler jwtAccessDeniedHandler;
@Resource
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Resource
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// 禁用session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
//login 不拦截
.antMatchers(“/login”).permitAll()
.antMatchers(HttpMethod.OPTIONS, “/**”).permitAll()
.antMatchers(“/”).permitAll()
.anyRequest().authenticated();
//用户访问没有授权资源
http.exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler);
//授权错误信息处理
//用户访问资源没有携带正确的token
http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
// 使用自己定义的拦截机制验证请求是否正确,拦截jwt
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
7、创建控制器
@RestController
public class UserController {
@Resource
private JwtUtil jwtUtil;
@Resource
private UserDetailsServiceImpl userDetailsService;
@PostMapping(“/login”)
public String login(@RequestBody UserVO userVO) {
//生成token,返回给客户端
UserDetails userDetails = userDetailsService.loadUserByUsername(userVO.getUsername());
String token = jwtUtil.generateToken(userDetails);
return token;
}
@GetMapping(“/fun1”)
userVO) {
//生成token,返回给客户端
UserDetails userDetails = userDetailsService.loadUserByUsername(userVO.getUsername());
String token = jwtUtil.generateToken(userDetails);
return token;
}
@GetMapping(“/fun1”)