【7.2.2】增加单点客户端根据CaClientToken销毁session机制

pull/29/head
fengshuonan 2022-05-20 14:29:21 +08:00
parent a6329ab656
commit c7ca6a5842
9 changed files with 263 additions and 74 deletions

View File

@ -122,4 +122,9 @@ public interface AuthConstants {
*/ */
String SYS_AUTH_SSO_GET_LOGIN_CODE = "/sso/getLoginCode"; String SYS_AUTH_SSO_GET_LOGIN_CODE = "/sso/getLoginCode";
/**
* tokentoken
*/
String CA_CLIENT_TOKEN_CACHE_PREFIX = "CA_CLIENT:TOKEN:";
} }

View File

@ -130,6 +130,9 @@ public class AuthServiceImpl implements AuthServiceApi {
@Resource(name = "loginErrorCountCacheApi") @Resource(name = "loginErrorCountCacheApi")
private CacheOperatorApi<Integer> loginErrorCountCacheApi; private CacheOperatorApi<Integer> loginErrorCountCacheApi;
@Resource(name = "caClientTokenCacheApi")
private CacheOperatorApi<String> caClientTokenCacheApi;
@Override @Override
public LoginResponse login(LoginRequest loginRequest) { public LoginResponse login(LoginRequest loginRequest) {
return loginAction(loginRequest, true, null); return loginAction(loginRequest, true, null);
@ -192,7 +195,12 @@ public class AuthServiceImpl implements AuthServiceApi {
throw new AuthException(AuthExceptionEnum.SSO_TOKEN_DECRYPT_USER_ERROR); throw new AuthException(AuthExceptionEnum.SSO_TOKEN_DECRYPT_USER_ERROR);
} }
return loginWithUserNameAndCaToken(account, caToken); LoginResponse loginResponse = loginWithUserNameAndCaToken(account, caToken);
// 存储单点token和生成的本地token的映射关系
caClientTokenCacheApi.put(loginWithTokenRequest.getToken(), loginResponse.getToken());
return loginResponse;
} }
@Override @Override
@ -208,7 +216,6 @@ public class AuthServiceImpl implements AuthServiceApi {
logoutWithToken(token); logoutWithToken(token);
sessionManagerApi.destroySessionCookie(); sessionManagerApi.destroySessionCookie();
} }
@Override @Override

View File

@ -0,0 +1,53 @@
/*
* Copyright [2020-2030] [https://www.stylefeng.cn]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* GunsAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Guns
* 3.
* 4. https://gitee.com/stylefeng/guns
* 5. https://gitee.com/stylefeng/guns
* 6.
*/
package cn.stylefeng.roses.kernel.auth.session.cache.catoken;
import cn.hutool.cache.impl.TimedCache;
import cn.stylefeng.roses.kernel.cache.memory.AbstractMemoryCacheOperator;
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.CA_CLIENT_TOKEN_CACHE_PREFIX;
/**
* tokentoken
* <p>
* key token
* value token
*
* @author fengshuonan
* @date 2022/5/20 11:40
*/
public class MemoryCaClientTokenCache extends AbstractMemoryCacheOperator<String> {
public MemoryCaClientTokenCache(TimedCache<String, String> timedCache) {
super(timedCache);
}
@Override
public String getCommonKeyPrefix() {
return CA_CLIENT_TOKEN_CACHE_PREFIX;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright [2020-2030] [https://www.stylefeng.cn]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* GunsAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Guns
* 3.
* 4. https://gitee.com/stylefeng/guns
* 5. https://gitee.com/stylefeng/guns
* 6.
*/
package cn.stylefeng.roses.kernel.auth.session.cache.catoken;
import cn.stylefeng.roses.kernel.cache.redis.AbstractRedisCacheOperator;
import org.springframework.data.redis.core.RedisTemplate;
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.CA_CLIENT_TOKEN_CACHE_PREFIX;
/**
* tokentoken
* <p>
* key token
* value token
*
* @author fengshuonan
* @date 2022/5/20 11:37
*/
public class RedisCaClientTokenCache extends AbstractRedisCacheOperator<String> {
public RedisCaClientTokenCache(RedisTemplate<String, String> redisTemplate) {
super(redisTemplate);
}
@Override
public String getCommonKeyPrefix() {
return CA_CLIENT_TOKEN_CACHE_PREFIX;
}
}

View File

@ -24,8 +24,6 @@
*/ */
package cn.stylefeng.roses.kernel.auth.starter; package cn.stylefeng.roses.kernel.auth.starter;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi; import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.auth.api.cookie.SessionCookieCreator; import cn.stylefeng.roses.kernel.auth.api.cookie.SessionCookieCreator;
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander; import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
@ -35,12 +33,9 @@ import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.auth.password.BcryptPasswordStoredEncrypt; import cn.stylefeng.roses.kernel.auth.password.BcryptPasswordStoredEncrypt;
import cn.stylefeng.roses.kernel.auth.password.RsaPasswordTransferEncrypt; import cn.stylefeng.roses.kernel.auth.password.RsaPasswordTransferEncrypt;
import cn.stylefeng.roses.kernel.auth.session.DefaultSessionManager; import cn.stylefeng.roses.kernel.auth.session.DefaultSessionManager;
import cn.stylefeng.roses.kernel.auth.session.cache.logintoken.MemoryLoginTokenCache;
import cn.stylefeng.roses.kernel.auth.session.cache.loginuser.MemoryLoginUserCache;
import cn.stylefeng.roses.kernel.auth.session.cookie.DefaultSessionCookieCreator; import cn.stylefeng.roses.kernel.auth.session.cookie.DefaultSessionCookieCreator;
import cn.stylefeng.roses.kernel.auth.session.timer.ClearInvalidLoginUserCacheTimer; import cn.stylefeng.roses.kernel.auth.session.timer.ClearInvalidLoginUserCacheTimer;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi; import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import cn.stylefeng.roses.kernel.cache.api.constants.CacheConstants;
import cn.stylefeng.roses.kernel.jwt.JwtTokenOperator; import cn.stylefeng.roses.kernel.jwt.JwtTokenOperator;
import cn.stylefeng.roses.kernel.jwt.api.JwtApi; import cn.stylefeng.roses.kernel.jwt.api.JwtApi;
import cn.stylefeng.roses.kernel.jwt.api.pojo.config.JwtConfig; import cn.stylefeng.roses.kernel.jwt.api.pojo.config.JwtConfig;
@ -117,37 +112,6 @@ public class GunsAuthAutoConfiguration {
return new DefaultSessionCookieCreator(); return new DefaultSessionCookieCreator();
} }
/**
* 使
* <p>
* redis loginUserCache bean
*
* @author fengshuonan
* @date 2021/1/31 21:04
*/
@Bean
@ConditionalOnMissingBean(name = "loginUserCache")
public CacheOperatorApi<LoginUser> loginUserCache() {
Long sessionExpiredSeconds = AuthConfigExpander.getSessionExpiredSeconds();
TimedCache<String, LoginUser> loginUsers = CacheUtil.newTimedCache(1000L * sessionExpiredSeconds);
return new MemoryLoginUserCache(loginUsers);
}
/**
* token使
* <p>
* redis allPlaceLoginTokenCache bean
*
* @author fengshuonan
* @date 2021/1/31 21:04
*/
@Bean
@ConditionalOnMissingBean(name = "allPlaceLoginTokenCache")
public CacheOperatorApi<Set<String>> allPlaceLoginTokenCache() {
TimedCache<String, Set<String>> loginTokens = CacheUtil.newTimedCache(CacheConstants.NONE_EXPIRED_TIME);
return new MemoryLoginTokenCache(loginTokens);
}
/** /**
* session便 * session便
* <p> * <p>
@ -171,8 +135,8 @@ public class GunsAuthAutoConfiguration {
*/ */
@Bean @Bean
@ConditionalOnMissingBean(ClearInvalidLoginUserCacheTimer.class) @ConditionalOnMissingBean(ClearInvalidLoginUserCacheTimer.class)
public ClearInvalidLoginUserCacheTimer clearInvalidLoginUserCacheTimer() { public ClearInvalidLoginUserCacheTimer clearInvalidLoginUserCacheTimer(CacheOperatorApi<LoginUser> loginUserCache, CacheOperatorApi<Set<String>> allPlaceLoginTokenCache) {
return new ClearInvalidLoginUserCacheTimer(loginUserCache(), allPlaceLoginTokenCache()); return new ClearInvalidLoginUserCacheTimer(loginUserCache, allPlaceLoginTokenCache);
} }
} }

View File

@ -0,0 +1,112 @@
/*
* Copyright [2020-2030] [https://www.stylefeng.cn]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* GunsAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Guns
* 3.
* 4. https://gitee.com/stylefeng/guns
* 5. https://gitee.com/stylefeng/guns
* 6.
*/
package cn.stylefeng.roses.kernel.auth.starter;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants;
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.auth.cache.LoginErrorCountMemoryCache;
import cn.stylefeng.roses.kernel.auth.session.cache.catoken.MemoryCaClientTokenCache;
import cn.stylefeng.roses.kernel.auth.session.cache.logintoken.MemoryLoginTokenCache;
import cn.stylefeng.roses.kernel.auth.session.cache.loginuser.MemoryLoginUserCache;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Set;
import static cn.stylefeng.roses.kernel.cache.api.constants.CacheConstants.NONE_EXPIRED_TIME;
/**
*
*
* @author fengshuonan
* @date 2020/11/30 22:16
*/
@Configuration
public class GunsAuthTokenCacheAutoConfiguration {
/**
* 使
* <p>
* redis loginUserCache bean
*
* @author fengshuonan
* @date 2021/1/31 21:04
*/
@Bean
@ConditionalOnMissingBean(name = "loginUserCache")
public CacheOperatorApi<LoginUser> loginUserCache() {
Long sessionExpiredSeconds = AuthConfigExpander.getSessionExpiredSeconds();
TimedCache<String, LoginUser> loginUsers = CacheUtil.newTimedCache(1000L * sessionExpiredSeconds);
return new MemoryLoginUserCache(loginUsers);
}
/**
* token使
* <p>
* redis allPlaceLoginTokenCache bean
*
* @author fengshuonan
* @date 2021/1/31 21:04
*/
@Bean
@ConditionalOnMissingBean(name = "allPlaceLoginTokenCache")
public CacheOperatorApi<Set<String>> allPlaceLoginTokenCache() {
TimedCache<String, Set<String>> loginTokens = CacheUtil.newTimedCache(NONE_EXPIRED_TIME);
return new MemoryLoginTokenCache(loginTokens);
}
/**
*
*
* @author fengshuonan
* @date 2022/3/15 17:25
*/
@Bean
@ConditionalOnMissingBean(name = "loginErrorCountCacheApi")
public CacheOperatorApi<Integer> loginErrorCountCacheApi() {
TimedCache<String, Integer> loginTimeCache = CacheUtil.newTimedCache(LoginCacheConstants.LOGIN_CACHE_TIMEOUT_SECONDS * 1000);
return new LoginErrorCountMemoryCache(loginTimeCache);
}
/**
* CaClienttoken
*
* @author fengshuonan
* @date 2022/5/20 11:52
*/
@Bean
@ConditionalOnMissingBean(name = "caClientTokenCacheApi")
public CacheOperatorApi<String> caClientTokenCacheApi() {
TimedCache<String, String> loginTimeCache = CacheUtil.newTimedCache(NONE_EXPIRED_TIME);
return new MemoryCaClientTokenCache(loginTimeCache);
}
}

View File

@ -1,33 +0,0 @@
package cn.stylefeng.roses.kernel.auth.starter;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants;
import cn.stylefeng.roses.kernel.auth.cache.LoginErrorCountMemoryCache;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
*
* @author fengshuonan
* @date 2022/3/15 17:26
*/
@Configuration
public class GunsLoginCacheAutoConfiguration {
/**
*
*
* @author fengshuonan
* @date 2022/3/15 17:25
*/
@Bean
@ConditionalOnMissingBean(name = "loginErrorCountCacheApi")
public CacheOperatorApi<Integer> loginErrorCountCacheApi() {
TimedCache<String, Integer> loginTimeCache = CacheUtil.newTimedCache(LoginCacheConstants.LOGIN_CACHE_TIMEOUT_SECONDS * 1000);
return new LoginErrorCountMemoryCache(loginTimeCache);
}
}

View File

@ -1,4 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.stylefeng.roses.kernel.auth.starter.GunsAuthAutoConfiguration,\ cn.stylefeng.roses.kernel.auth.starter.GunsAuthAutoConfiguration,\
cn.stylefeng.roses.kernel.auth.starter.GunsSsoAutoConfiguration,\ cn.stylefeng.roses.kernel.auth.starter.GunsSsoAutoConfiguration,\
cn.stylefeng.roses.kernel.auth.starter.GunsLoginCacheAutoConfiguration cn.stylefeng.roses.kernel.auth.starter.GunsAuthTokenCacheAutoConfiguration

View File

@ -24,6 +24,7 @@
*/ */
package cn.stylefeng.roses.kernel.system.modular.user.controller; package cn.stylefeng.roses.kernel.system.modular.user.controller;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi; import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi;
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi; import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext; import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
@ -31,6 +32,7 @@ import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse; import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginWithTokenRequest; import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginWithTokenRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser; import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData; import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData;
import cn.stylefeng.roses.kernel.rule.pojo.response.SuccessResponseData; import cn.stylefeng.roses.kernel.rule.pojo.response.SuccessResponseData;
import cn.stylefeng.roses.kernel.scanner.api.annotation.ApiResource; import cn.stylefeng.roses.kernel.scanner.api.annotation.ApiResource;
@ -45,6 +47,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -70,6 +73,9 @@ public class LoginController {
@Resource @Resource
private IndexUserInfoService indexUserInfoService; private IndexUserInfoService indexUserInfoService;
@Resource(name = "caClientTokenCacheApi")
private CacheOperatorApi<String> caClientTokenCacheApi;
/** /**
* *
* *
@ -108,6 +114,28 @@ public class LoginController {
return new SuccessResponseData<>(loginResponse.getToken()); return new SuccessResponseData<>(loginResponse.getToken());
} }
/**
* 退CaClientToken退
*
* @param caClientToken tokentoken
* @author fengshuonan
* @date 2021/3/17 17:24
*/
@ApiResource(name = "单点退出", path = "/logoutByCaClientToken", requiredLogin = false, requiredPermission = false, method = {RequestMethod.GET, RequestMethod.POST})
public ResponseData<?> ssoLogout(@RequestParam("caClientToken") String caClientToken) {
// 获取CaClientToken对应的本地用户
String currentSystemToken = caClientTokenCacheApi.get(caClientToken);
if (StrUtil.isNotBlank(currentSystemToken)) {
// 移除本系统中token
authServiceApi.logoutWithToken(currentSystemToken);
caClientTokenCacheApi.remove(caClientToken);
}
return new SuccessResponseData<>();
}
/** /**
* *
* *