From 4b6e2e02c0da979376428b4bdaf1cb409003edfe Mon Sep 17 00:00:00 2001 From: Hansin1997 <845612500@qq.com> Date: Sat, 13 Mar 2021 12:28:25 +0800 Subject: [PATCH] =?UTF-8?q?v1.0.4-alpha-3:=20=E7=A6=81=E7=94=A8=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BB=A5=E5=8F=8A=E5=88=A0=E9=99=A4=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=90=8C=E6=97=B6=E5=88=A0=E9=99=A4=E5=85=B6?= =?UTF-8?q?=E6=89=80=E6=9C=89=20AccessToken=20=E5=92=8C=20RefreshToken?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth-core/pom.xml | 2 +- auth-service/pom.xml | 2 +- .../components/TokenConfiguration.java | 5 +- .../controllers/resources/UserResource.java | 20 ++++++++ .../oauth/EnhancedRedisTokenStore.java | 50 ++++++++++++++++++- pom.xml | 2 +- 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/auth-core/pom.xml b/auth-core/pom.xml index c5e32355..d1f80390 100644 --- a/auth-core/pom.xml +++ b/auth-core/pom.xml @@ -5,7 +5,7 @@ cn.dustlight.auth auth-parent - 1.0.4-alpha-2 + 1.0.4-alpha-3 ../pom.xml auth-core diff --git a/auth-service/pom.xml b/auth-service/pom.xml index d69428d8..aedfc910 100644 --- a/auth-service/pom.xml +++ b/auth-service/pom.xml @@ -5,7 +5,7 @@ cn.dustlight.auth auth-parent - 1.0.4-alpha-2 + 1.0.4-alpha-3 ../pom.xml auth-service diff --git a/auth-service/src/main/java/cn/dustlight/auth/configurations/components/TokenConfiguration.java b/auth-service/src/main/java/cn/dustlight/auth/configurations/components/TokenConfiguration.java index bf6a822e..aac9d17a 100644 --- a/auth-service/src/main/java/cn/dustlight/auth/configurations/components/TokenConfiguration.java +++ b/auth-service/src/main/java/cn/dustlight/auth/configurations/components/TokenConfiguration.java @@ -31,8 +31,9 @@ public RedisTokenStore authTokenStore(@Autowired RedisConnectionFactory redisCon @Bean("enhancedTokenStore") @ConditionalOnMissingBean(name = "enhancedTokenStore") - public EnhancedRedisTokenStore enhancedRedisTokenStore(@Autowired RedisConnectionFactory redisConnectionFactory) { - return new EnhancedRedisTokenStore(redisConnectionFactory); + public EnhancedRedisTokenStore enhancedRedisTokenStore(@Autowired RedisConnectionFactory redisConnectionFactory, + @Autowired RedisTokenStore redisTokenStore) { + return new EnhancedRedisTokenStore(redisConnectionFactory, redisTokenStore); } @Bean("authApprovalStore") diff --git a/auth-service/src/main/java/cn/dustlight/auth/controllers/resources/UserResource.java b/auth-service/src/main/java/cn/dustlight/auth/controllers/resources/UserResource.java index 79ba61f8..ffc054c8 100644 --- a/auth-service/src/main/java/cn/dustlight/auth/controllers/resources/UserResource.java +++ b/auth-service/src/main/java/cn/dustlight/auth/controllers/resources/UserResource.java @@ -5,6 +5,7 @@ import cn.dustlight.auth.entities.DefaultUser; import cn.dustlight.auth.entities.DefaultUserRole; import cn.dustlight.auth.entities.User; +import cn.dustlight.auth.services.oauth.EnhancedRedisTokenStore; import cn.dustlight.auth.services.storages.StorageHandler; import cn.dustlight.auth.services.UserService; import cn.dustlight.auth.util.Constants; @@ -53,6 +54,9 @@ public class UserResource { @Autowired protected StorageHandler storageHandler; + @Autowired + protected EnhancedRedisTokenStore enhancedRedisTokenStore; + /** * 判断 Client 与用户是否拥有某权限。 */ @@ -101,12 +105,20 @@ public User createUser(@RequestParam(name = "username") String username, @DeleteMapping("users/{uid}") @io.swagger.v3.oas.annotations.Operation(summary = "删除用户(永久删除)", description = "应用和用户需要 DELETE_USER 权限。") public void deleteUser(@PathVariable Long uid) { + DefaultUser user = userService.loadUser(uid); + if (user == null) + ErrorEnum.USER_NOT_FOUND.throwException(); userService.deleteUsers(Arrays.asList(uid)); try { storageHandler.remove(generateAvatarKey(uid)); } catch (Exception e) { ErrorEnum.DELETE_USER_AVATAR_FAIL.details(e.getMessage()); } + try { + enhancedRedisTokenStore.deleteUserToken(user.getUsername()); + } catch (IOException e) { + ErrorEnum.DELETE_USER_TOKEN_FAIL.throwException(); + } logger.debug(String.format("删除用户: [%s] ", uid)); } @@ -170,6 +182,14 @@ public void updateUserExpiredAt(@PathVariable Long uid, @RequestParam Date expir @Operation(summary = "设置用户封禁或解封", description = "封禁或解封用户。应用和用户需拥有 LOCK_USER 权限。") public void updateUserEnabled(@PathVariable Long uid, @RequestParam Boolean enabled) { userService.updateEnabled(Arrays.asList(uid), enabled); + if(!enabled){ + DefaultUser user = userService.loadUser(uid); + try { + enhancedRedisTokenStore.deleteUserToken(user.getUsername()); + } catch (IOException e) { + ErrorEnum.DELETE_USER_TOKEN_FAIL.throwException(); + } + } } @PreAuthorize("(#oauth2.client or hasAnyAuthority('WRITE_USER_EMAIL')) and #oauth2.clientHasRole('WRITE_USER_EMAIL')") diff --git a/auth-service/src/main/java/cn/dustlight/auth/services/oauth/EnhancedRedisTokenStore.java b/auth-service/src/main/java/cn/dustlight/auth/services/oauth/EnhancedRedisTokenStore.java index f2bba656..0ac977ab 100644 --- a/auth-service/src/main/java/cn/dustlight/auth/services/oauth/EnhancedRedisTokenStore.java +++ b/auth-service/src/main/java/cn/dustlight/auth/services/oauth/EnhancedRedisTokenStore.java @@ -1,19 +1,36 @@ package cn.dustlight.auth.services.oauth; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy; +import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy; +import java.io.IOException; +import java.util.Set; + public class EnhancedRedisTokenStore { private static final String CLIENT_ID_TO_ACCESS = "client_id_to_access:"; + + private static final String USERNAME_TO_ACCESS = "uname_to_access:"; + private RedisConnectionFactory redisConnectionFactory; + private RedisTokenStore redisTokenStore; private String prefix = ""; + private static final Log logger = LogFactory.getLog(EnhancedRedisTokenStore.class); + private RedisTokenStoreSerializationStrategy serializationStrategy = new JdkSerializationStrategy(); - public EnhancedRedisTokenStore(RedisConnectionFactory connectionFactory) { + public EnhancedRedisTokenStore(RedisConnectionFactory connectionFactory, RedisTokenStore redisTokenStore) { + this.redisTokenStore = redisTokenStore; this.redisConnectionFactory = connectionFactory; } @@ -29,6 +46,14 @@ protected byte[] serializeKey(String key) { return serializationStrategy.serialize(prefix + key); } + protected String deserializeKey(byte[] bytes) { + return serializationStrategy.deserializeString(bytes); + } + + protected T deserialize(byte[] bytes, Class clazz) { + return serializationStrategy.deserialize(bytes, clazz); + } + protected RedisConnection getConnection() { return this.redisConnectionFactory.getConnection(); } @@ -38,4 +63,27 @@ public Long countClientToken(String clientId) { return conn.setCommands().sCard(serializeKey(CLIENT_ID_TO_ACCESS + clientId)); } } + + public void deleteUserToken(String username) throws IOException { + try (RedisConnection conn = getConnection()) { + try (Cursor cursor = conn.keyCommands().scan(ScanOptions.scanOptions() + .match(USERNAME_TO_ACCESS + "*:" + username) + .count(Long.MAX_VALUE) + .build())) { + cursor.forEachRemaining(bytes -> { + String key = deserializeKey(bytes); + Set tokenSet = conn.sMembers(bytes); + if (tokenSet == null) + return; + tokenSet.forEach(tokenBytes -> { + DefaultOAuth2AccessToken accessToken = deserialize(tokenBytes, DefaultOAuth2AccessToken.class); + redisTokenStore.removeAccessToken(accessToken); + OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); + if (refreshToken != null) + redisTokenStore.removeRefreshToken(refreshToken); + }); + }); + } + } + } } diff --git a/pom.xml b/pom.xml index 86e93575..814e0b6c 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ cn.dustlight.auth auth-parent auth-parent - 1.0.4-alpha-2 + 1.0.4-alpha-3 Parent project of OAuth2 Server based on Spring Cloud Security