Rumah > Java > javaTutorial > teks badan

Cara SpringBoot Security melaksanakan log keluar tunggal dan mengosongkan semua token

WBOY
Lepaskan: 2023-05-14 13:43:11
ke hadapan
2063 orang telah melayarinya

Keperluan

  • Sistem A, B dan C boleh log masuk melalui perkhidmatan sso

  • Sistem A, B dan C memperoleh Atoken dan Btoken masing-masing , Ctoken tiga token

  • Selepas salah satu sistem log keluar secara aktif, dua sistem lain turut log keluar

  • Setakat ini semua Atoken dan Btoken , Ctoken tidak sah

Token rekod

fail pom memperkenalkan kebergantungan

  • Kebergantungan pangkalan data Redis

  • hutool: digunakan untuk menghuraikan token

<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>
Salin selepas log masuk

kelas storan token melaksanakan AuthJdbcTokenStore

  • TokenStore>mewarisi JdbcToken>

  • Gunakan nama pengguna pengguna log masuk sebagai kunci Redis

  • Oleh kerana akan terdapat berbilang sistem di mana pengguna log masuk, nilai menggunakan Jenis senarai redis untuk menyimpan token

  • Tetapkan masa sah untuk memastikan bahawa ia tidak kurang daripada masa sah maksimum token dalam senarai

  • @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;
        }
    }
    Salin selepas log masuk
oauth_access_token Menggunakan JdbcTokenStore untuk menyimpan token memerlukan jadual baharu

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;
Salin selepas log masuk

AuthorizationServerConfigurerAdapter menggunakan AuthJdbcTokenStore untuk storan token

  • Melalui kaedah Pembinaan Jbc. dalam DataSource

  • Buat TokenStore Gunakan AuthJdbcTokenStore untuk melaksanakan

  • tokenServices Tambah TokenStore

  • <🎜 Tambah 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)
            ;
        }
    	...
    }
    Salin selepas log masuk
Kosongkan token

  • Warisi SimpleUrlLogoutSuccessHandler

  • Dapatkan nama pengguna

  • Dapatkan senarai token yang disimpan dalam Redis semasa log masuk
  • Rentetan token ditukar kepada OAuth3AccessToken
  • Gunakan tokenStore untuk memadam token
  • @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);
            }
        }
    }
    Salin selepas log masuk
  • Untuk menyelesaikan masa log keluar Terlalu lama

Senario: Selepas projek telah berjalan untuk satu tempoh masa, didapati bahawa masa log keluar semakin perlahan dan semakin perlahan

Masalah: Melalui penyahpepijatan, didapati bahawa memakan masa adalah terutamanya dalam tempoh pemadaman token

tokenStore.removeAccessToken(token);
Salin selepas log masuk

Sebab: Semakin masa berlalu, semakin banyak dan lebih banyak token dan jadual storan token oauth_access_token menjadi luar biasa besar, jadi kecekapan pemadaman sangat lemah

Penyelesaian: Gunakan TokenStore lain, atau kosongkan data jadual oauth_access_token

Atas ialah kandungan terperinci Cara SpringBoot Security melaksanakan log keluar tunggal dan mengosongkan semua token. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:yisu.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan