A, B, C 시스템은 sso 서비스를 통해 로그인
A, B, C 시스템은 각각 Atoken, Btoken, Ctoken 3개의 토큰을 얻습니다
시스템 중 하나 이후 적극적으로 로그아웃합니다. 다른 두 시스템도 로그아웃되었습니다
이제 모든 Atoken, Btoken 및 Ctoken이 유효하지 않습니다
pom 파일에 종속성이 발생합니다
Redis 데이터베이스 종속성
hutool: 토큰을 구문 분석하는 데 사용됨
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.13</version> </dependency>
Token 저장소 클래스는 AuthJdbcTokenStore
TokenStore가 JdbcTokenStore를 상속함
로그인한 사용자 사용자 이름의 사용자 이름을 Redis 키로 사용
사용자가 로그인하므로 값은 Redis 목록을 사용합니다. 토큰을 저장하려면 입력하세요
목록에 있는 토큰의 최대 유효 시간보다 작지 않도록 유효 시간을 설정하세요
@Component public class AuthJdbcTokenStore extends JdbcTokenStore { public static final String USER_HAVE_TOKEN = "user-tokens:"; @Resource RedisTemplate redisTemplate; public AuthJdbcTokenStore(DataSource connectionFactory) { super(connectionFactory); } @Override public void storeAccessToken(OAuth3AccessToken token, OAuth3Authentication authentication) { super.storeAccessToken(token, authentication); if (Optional.ofNullable(authentication.getUserAuthentication()).isPresent()) { User user = (User) authentication.getUserAuthentication().getPrincipal(); String userTokensKey = USER_HAVE_TOKEN + user.getUsername(); String tokenValue = token.getValue(); redisTemplate.opsForList().leftPush(userTokensKey, tokenValue); Long seconds = redisTemplate.opsForValue().getOperations().getExpire(userTokensKey); Long tokenExpTime = getExpTime(tokenValue); Long expTime = seconds < tokenExpTime ? tokenExpTime : seconds; redisTemplate.expire(userTokensKey, expTime, TimeUnit.SECONDS); } } private long getExpTime(String accessToken) { JWT jwt = JWTUtil.parseToken(accessToken); cn.hutool.json.JSONObject jsonObject = jwt.getPayload().getClaimsJson(); long nowTime = Instant.now().getEpochSecond(); long expEndTime = jsonObject.getLong("exp"); long expTime = (expEndTime - nowTime); return expTime; } }
oauth_access_token JdbcTokenStore 사용 토큰을 저장하려면 새 테이블을 추가해야 합니다
CREATE TABLE `oauth_access_token` ( `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `token_id` varchar(255) DEFAULT NULL, `token` blob, `authentication_id` varchar(255) DEFAULT NULL, `user_name` varchar(255) DEFAULT NULL, `client_id` varchar(255) DEFAULT NULL, `authentication` blob, `refresh_token` varchar(255) DEFAULT NULL, UNIQUE KEY `authentication_id` (`authentication_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
AuthorizationServerConfigurerAdapter 토큰 저장을 위해 AuthJdbcTokenStore를 사용하세요.
JdbcTokenStore의 생성자가 DataSource
를 생성하고 AuthJdbcTokenStore
로 전달해야 하므로 DataSource를 도입하세요.tokenServices TokenStore 추가
endpoints 추가 tokenServices
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private DataSource dataSource; ... @Bean public TokenStore tokenStore() { JdbcTokenStore tokenStore = new AuthJdbcTokenStore(dataSource); return tokenStore; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore()); endpoints .authenticationManager(authenticationManager) .tokenServices(tokenServices) .accessTokenConverter(converter) ; } ... }
inherits SimpleUrlLogoutSuccessHandler
사용자 이름 userName
로그인 시 Redis에 저장된 토큰 목록 가져오기
token 문자열은 OAuth3AccessToken으로 변환됩니다
tokenStore를 사용하여 토큰을 삭제하세요
@Component public class AuthLogoutSuccessHandler1 extends SimpleUrlLogoutSuccessHandler { String USER_HAVE_TOKEN = AuthJdbcTokenStore.USER_HAVE_TOKEN; @Resource RedisTemplate redisTemplate; @Resource TokenStore tokenStore; @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { if (!Objects.isNull(authentication)) { String userName = authentication.getName(); String userTokensKey = USER_HAVE_TOKEN + userName; Long size = redisTemplate.opsForList().size(userTokensKey); List<String> list = redisTemplate.opsForList().range(userTokensKey, 0, size); for (String tokenValue : list) { OAuth3AccessToken token = tokenStore.readAccessToken(tokenValue); if (Objects.nonNull(token)) { tokenStore.removeAccessToken(token); } } redisTemplate.delete(userTokensKey); super.handle(request, response, authentication); } } }
시나리오: 프로젝트가 일정 시간 동안 실행된 후 로그아웃 시간이 점점 느려지고 있어요
문제: 디버깅을 통해 주로 토큰을 삭제하는 기간에 시간이 많이 소요되는 것으로 나타났습니다
tokenStore.removeAccessToken(token);
원인: 시간이 지날수록 저장 테이블 oauth_access_token에 토큰이 많아집니다. 비정상적으로 커져서 삭제 효율성이 매우 떨어집니다
해결책: 다른 TokenStore를 사용하거나 oauth_access_token의 테이블 데이터를 삭제하세요
위 내용은 SpringBoot Security가 싱글 사인아웃을 구현하고 모든 토큰을 지우는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!