Jwt退出登录

This commit is contained in:
Amadeus 2024-04-22 23:11:18 +08:00
parent 02a294df0e
commit a6d7af1784
4 changed files with 58 additions and 7 deletions

View File

@ -52,6 +52,10 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.auth0</groupId> <groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId> <artifactId>java-jwt</artifactId>

View File

@ -23,6 +23,7 @@ import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
@Configuration @Configuration
public class SecurityConfiguration { public class SecurityConfiguration {
@ -54,10 +55,6 @@ public class SecurityConfiguration {
//用户登录了但没有权限访问一些资源 //用户登录了但没有权限访问一些资源
.accessDeniedHandler(this::onAccessDeny) .accessDeniedHandler(this::onAccessDeny)
) )
.csrf(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable)
.sessionManagement(conf -> conf .sessionManagement(conf -> conf
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
@ -106,6 +103,13 @@ public class SecurityConfiguration {
public void onLogoutSuccess(HttpServletRequest request, public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException { Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
String authorization = request.getHeader("Authorization");
if (utils.invalidateJwt(authorization)){
writer.write(RestBean.success().asJsonString());
}else {
writer.write(RestBean.failure(400,"退出登录失败").asJsonString());
}
} }
} }

View File

@ -0,0 +1,5 @@
package com.example.utils;
public class Const {
public static final String JWT_BLACK_LIST = "jwt:blacklist:";
}

View File

@ -6,8 +6,10 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@ -16,6 +18,8 @@ import org.springframework.stereotype.Component;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Component @Component
public class JwtUtils { public class JwtUtils {
@ -25,16 +29,48 @@ public class JwtUtils {
@Value("${spring.security.jwt.expire}") @Value("${spring.security.jwt.expire}")
int expire; int expire;
@Resource
StringRedisTemplate template;
//添加让jwt令牌失效的方法
public boolean invalidateJwt(String headerToken){
String token =this.convertToken(headerToken);
if (token == null ) return false;
Algorithm algorithm = Algorithm.HMAC256(key);
JWTVerifier jwtVerifier = JWT.require(algorithm).build();
try {
DecodedJWT jwt = jwtVerifier.verify(token);
String id = jwt.getId();
return deleteToken(id ,jwt.getExpiresAt());
}catch (JWTVerificationException e){
return false;
}
}
private boolean deleteToken(String uuid , Date time){
if (this.isInvalidToken(uuid))
return false;
Date now = new Date();
long expire = Math.max(time.getTime() - now.getTime() , 0 );
template.opsForValue().set(Const.JWT_BLACK_LIST + uuid , "" ,expire , TimeUnit.MILLISECONDS);
return true;
}
private boolean isInvalidToken(String uuid){
return Boolean.TRUE.equals(template.hasKey(Const.JWT_BLACK_LIST + uuid));
}
//解析jwt //解析jwt
public DecodedJWT resolverJwt(String headerToken){ public DecodedJWT resolverJwt(String headerToken){
String token =this.convertToken(headerToken); String token =this.convertToken(headerToken);
if (token == null ) return null; if (token == null ) return null;
Algorithm algorithm = Algorithm.HMAC256(key); Algorithm algorithm = Algorithm.HMAC256(key);
JWTVerifier jwtVerifier = JWT.require(algorithm).build(); JWTVerifier jwtVerifier = JWT.require(algorithm).build();
//验证jwt是否被用户篡改过,是的话抛出异常
try { try {
DecodedJWT verify = jwtVerifier.verify(token); DecodedJWT verify = jwtVerifier.verify(token);
Date expiresAt = verify.getExpiresAt(); //判断token是否过期 if (this.isInvalidToken(verify.getId()))
return null;
Date expiresAt = verify.getExpiresAt();
return new Date().after(expiresAt) ? null : verify; return new Date().after(expiresAt) ? null : verify;
} catch (JWTVerificationException e) { } catch (JWTVerificationException e) {
@ -70,6 +106,8 @@ public class JwtUtils {
Algorithm algorithm = Algorithm.HMAC256(key); Algorithm algorithm = Algorithm.HMAC256(key);
Date expire = this.expireTime(); Date expire = this.expireTime();
return JWT.create() return JWT.create()
//让每个令牌生成一个随机的uuid
.withJWTId(UUID.randomUUID().toString())
.withClaim("id",id) .withClaim("id",id)
.withClaim("name",username) .withClaim("name",username)
.withClaim("authorities",details.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList()) .withClaim("authorities",details.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList())