Jwt退出登录
This commit is contained in:
parent
02a294df0e
commit
a6d7af1784
4
pom.xml
4
pom.xml
|
@ -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>
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.example.utils;
|
||||||
|
|
||||||
|
public class Const {
|
||||||
|
public static final String JWT_BLACK_LIST = "jwt:blacklist:";
|
||||||
|
}
|
|
@ -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())
|
||||||
|
|
Loading…
Reference in New Issue