Maison >Java >javaDidacticiel >Comment SpringBoot Security implémente la déconnexion unique et efface tous les jetons

Comment SpringBoot Security implémente la déconnexion unique et efface tous les jetons

WBOY
WBOYavant
2023-05-14 13:43:112122parcourir

Exigences

  • Les systèmes A, B et C implémentent la connexion via le service sso

  • A, les systèmes B et C obtiennent respectivement Atoken, Btoken et Ctoken

  • À ce stade, tous les Atoken, Btoken et Ctoken sont invalides

  • .
  • Record token

    le fichier pom introduit des dépendances

Dépendance de la base de données Redis

    # 🎜🎜#hutool : utilisé pour analyser le jeton
  • # 🎜🎜#

    <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>

    la classe de stockage de jetons implémente AuthJdbcTokenStore
  • TokenStore hérite JdbcTokenStore

Utiliser la connexion Le nom d'utilisateur de l'utilisateur est utilisé comme clé Redis
  • Parce que l'utilisateur se connecte à plusieurs systèmes , la valeur utilise le type de liste Redis pour stocker le jeton
  • # 🎜🎜#
  • Définissez la durée de validité pour vous assurer qu'elle n'est pas inférieure à la durée de validité maximale du jeton dans la liste

  • @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 L'utilisation de JdbcTokenStore pour stocker les jetons nécessite un nouveau L'ajout d'une table

    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 utilise AuthJdbcTokenStore pour le stockage des jetons#🎜 🎜##🎜🎜 #
  • Présentation de DataSource, car la méthode de construction de JdbcTokenStore doit passer dans DataSource#🎜 🎜## 🎜🎜#

  • Créer TokenStore et l'implémenter avec AuthJdbcTokenStore
# 🎜🎜#

tokenServices Ajouter TokenStore

# 🎜🎜## 🎜🎜#endpoints Ajouter 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)
            ;
        }
    	...
    }
    # 🎜🎜# Effacer le jeton

  • Inherits SimpleUrlLogoutSuccessHandler#🎜 🎜##🎜🎜 #

  • Obtenir le nom d'utilisateur userName
  • #🎜 🎜#

    Obtenir la liste des jetons stockée dans Redis lors de la connexion
  • La chaîne de jetons est convertie en OAuth3AccessToken

Utilisez tokenStore pour supprimer le jeton
  • @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);
            }
        }
    }

    Solution pour se déconnecter Trop longtemps
  • Scénario : Après que le projet ait été exécuté pendant un certain temps du temps, on constate que le temps de déconnexion devient de plus en plus lent

    Problème : Grâce au débogage, on constate que le temps prend principalement dans la période de suppression du token#🎜 🎜#
    tokenStore.removeAccessToken(token);
    # 🎜🎜#Cause : Au fil du temps, il y a de plus en plus de jetons, et la table de stockage des jetons oauth_access_token devient anormalement grande, donc l'efficacité de la suppression est très mauvaise
  • Solution : Utilisez un autre TokenStore, ou effacez les données de la table de oauth_access_token

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer