mirror of https://gitee.com/stylefeng/roses
【auth】增加创建session会写cookie的功能,增加systemConfig
parent
79bf2e4418
commit
a646cb67ce
|
@ -69,13 +69,7 @@ public interface AuthServiceApi {
|
|||
boolean getTokenFlag(String token);
|
||||
|
||||
/**
|
||||
* 校验用户访问的url是否认证通过
|
||||
* <p>
|
||||
* 校验会进行两方面:
|
||||
* <p>
|
||||
* 第一,校验用户的token是否过期
|
||||
* <p>
|
||||
* 第二,校验用户的session是否失效,但是记住我的session失效后会自动创建session,直到jwt失效后
|
||||
* 校验用户是否认证通过,认证是校验token的过程,校验失败会抛出异常
|
||||
*
|
||||
* @param token 用户登陆的token
|
||||
* @param requestUrl 被校验的url
|
||||
|
|
|
@ -54,4 +54,13 @@ public interface LoginUserApi {
|
|||
*/
|
||||
boolean getSuperAdminFlag();
|
||||
|
||||
/**
|
||||
* 判断当前用户是否登录
|
||||
*
|
||||
* @return 是否登录,true是,false否
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/17 11:02
|
||||
*/
|
||||
boolean hasLogin();
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public interface PermissionServiceApi {
|
|||
/**
|
||||
* 校验当前用户是否有某个接口的权限
|
||||
* <p>
|
||||
* 只要认证不通过,则会抛出异常
|
||||
* 只要权限校验不通过,则会抛出异常
|
||||
*
|
||||
* @param token 用户登陆的token
|
||||
* @param requestUrl 被校验的url
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package cn.stylefeng.roses.kernel.auth.api.cookie;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
/**
|
||||
* cookie的创建器,用在session创建时,给httpServletResponse添加cookie
|
||||
* <p>
|
||||
* 每个公司情况不一样,所以预留拓展接口
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 13:28
|
||||
*/
|
||||
public abstract class SessionCookieCreator {
|
||||
|
||||
/**
|
||||
* 创建cookie的操作
|
||||
* <p>
|
||||
* 这里不要重写这个方法,重写后名称对不上可能导致登录后权限校验失败
|
||||
*
|
||||
* @param cookieName cookie的名称
|
||||
* @param cookieValue cookie的值
|
||||
* @param sessionExpiredSeconds cookie过期时间
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 13:29
|
||||
*/
|
||||
public Cookie createCookie(String cookieName, String cookieValue, Integer sessionExpiredSeconds) {
|
||||
Cookie cookie = new Cookie(cookieName, cookieValue);
|
||||
cookie.setMaxAge(Convert.toInt(sessionExpiredSeconds));
|
||||
this.expandCookieProp(cookie);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拓展cookie的配置
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 13:41
|
||||
*/
|
||||
public abstract void expandCookieProp(Cookie cookie);
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ public class AuthConfigExpander {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取携带token的header头的名称
|
||||
* 获取携带token的param传参的名称
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/22 14:11
|
||||
|
@ -88,4 +88,32 @@ public class AuthConfigExpander {
|
|||
return ConfigContext.me().getSysConfigValueWithDefault("SYS_DEFAULT_PASSWORD", String.class, DEFAULT_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话信息是否增加保存在 cookie 中
|
||||
* <p>
|
||||
* 如果开启此开关,会发生两件事:
|
||||
* <p>
|
||||
* 1.则登录过程中创建会话时,会HttpServletResponse对象进行addCookie()操作
|
||||
* <p>
|
||||
* 2.获取当前用户token会多一个从cookie中获取token这个方式
|
||||
* <p>
|
||||
* 一般这个开关的开启,用在单体不分离的版本中
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 13:15
|
||||
*/
|
||||
public static Boolean getSessionAddToCookie() {
|
||||
return ConfigContext.me().getSysConfigValueWithDefault("SYS_SESSION_ADD_TO_COOKIE", Boolean.class, Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话保存在cookie中时,cooke的name
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 13:18
|
||||
*/
|
||||
public static String getSessionCookieName() {
|
||||
return ConfigContext.me().getSysConfigValueWithDefault("SYS_SESSION_COOKIE_NAME", String.class, DEFAULT_AUTH_HEADER_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum.TOKEN_GET_ERROR;
|
||||
|
@ -32,7 +33,7 @@ public class LoginUserImpl implements LoginUserApi {
|
|||
// 获取当前http请求
|
||||
HttpServletRequest request = HttpServletUtil.getRequest();
|
||||
|
||||
// 优先从param参数中获取token
|
||||
// 1. 优先从param参数中获取token
|
||||
String parameterToken = request.getParameter(AuthConfigExpander.getAuthTokenParamName());
|
||||
|
||||
// 不为空则直接返回param的token
|
||||
|
@ -40,12 +41,28 @@ public class LoginUserImpl implements LoginUserApi {
|
|||
return parameterToken;
|
||||
}
|
||||
|
||||
// 从header中获取token
|
||||
// 2. 从header中获取token
|
||||
String authToken = request.getHeader(AuthConfigExpander.getAuthTokenHeaderName());
|
||||
if (StrUtil.isNotBlank(authToken)) {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
// 3. 从cookie中获取token
|
||||
if (AuthConfigExpander.getSessionAddToCookie()) {
|
||||
String sessionCookieName = AuthConfigExpander.getSessionCookieName();
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null && cookies.length > 0) {
|
||||
for (Cookie cookie : cookies) {
|
||||
|
||||
// 如果cookie有对应的值,并且不为空
|
||||
if (sessionCookieName.equals(cookie.getName())
|
||||
&& StrUtil.isNotBlank(cookie.getValue())) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取不到token,直接告诉用户
|
||||
throw new AuthException(TOKEN_GET_ERROR);
|
||||
}
|
||||
|
@ -89,4 +106,19 @@ public class LoginUserImpl implements LoginUserApi {
|
|||
return loginUser.getSuperAdmin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLogin() {
|
||||
|
||||
// 获取用户的token
|
||||
String token = null;
|
||||
try {
|
||||
token = getToken();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取是否在会话中有
|
||||
return sessionManagerApi.haveSession(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
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.pojo.login.LoginUser;
|
||||
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
|
||||
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -38,10 +44,19 @@ public class DefaultSessionManager implements SessionManagerApi {
|
|||
*/
|
||||
private final Long sessionExpiredSeconds;
|
||||
|
||||
public DefaultSessionManager(CacheOperatorApi<LoginUser> loginUserCache, CacheOperatorApi<Set<String>> allPlaceLoginTokenCache, Long sessionExpiredSeconds) {
|
||||
/**
|
||||
* cookie的创建器,用在session创建时,给response添加cookie
|
||||
*/
|
||||
private final SessionCookieCreator sessionCookieCreator;
|
||||
|
||||
public DefaultSessionManager(CacheOperatorApi<LoginUser> loginUserCache,
|
||||
CacheOperatorApi<Set<String>> allPlaceLoginTokenCache,
|
||||
Long sessionExpiredSeconds,
|
||||
SessionCookieCreator sessionCookieCreator) {
|
||||
this.loginUserCache = loginUserCache;
|
||||
this.allPlaceLoginTokenCache = allPlaceLoginTokenCache;
|
||||
this.sessionExpiredSeconds = sessionExpiredSeconds;
|
||||
this.sessionCookieCreator = sessionCookieCreator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +72,15 @@ public class DefaultSessionManager implements SessionManagerApi {
|
|||
}
|
||||
theUserTokens.add(token);
|
||||
allPlaceLoginTokenCache.put(loginUser.getUserId().toString(), theUserTokens);
|
||||
|
||||
// 如果开启了cookie存储会话信息,则需要给HttpServletResponse添加一个cookie
|
||||
if (AuthConfigExpander.getSessionAddToCookie()) {
|
||||
String sessionCookieName = AuthConfigExpander.getSessionCookieName();
|
||||
Cookie cookie = sessionCookieCreator.createCookie(sessionCookieName, token, Convert.toInt(sessionExpiredSeconds));
|
||||
HttpServletResponse response = HttpServletUtil.getResponse();
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,7 +101,10 @@ public class DefaultSessionManager implements SessionManagerApi {
|
|||
Long userId = loginUser.getUserId();
|
||||
Set<String> userTokens = allPlaceLoginTokenCache.get(userId.toString());
|
||||
if (userTokens != null) {
|
||||
|
||||
// 清除对应的token的信息
|
||||
userTokens.remove(token);
|
||||
allPlaceLoginTokenCache.put(userId.toString(), userTokens);
|
||||
|
||||
// 如果删除后size为0,则把整个key删掉
|
||||
if (userTokens.size() == 0) {
|
||||
|
@ -101,6 +128,14 @@ public class DefaultSessionManager implements SessionManagerApi {
|
|||
// 获取用户id
|
||||
Long userId = session.getUserId();
|
||||
|
||||
// 获取这个用户多余的几个登录信息
|
||||
Set<String> thisUserTokens = allPlaceLoginTokenCache.get(userId.toString());
|
||||
for (String thisUserToken : thisUserTokens) {
|
||||
if (!thisUserToken.equals(token)) {
|
||||
loginUserCache.remove(thisUserToken);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置用户id对应的token列表为参数token
|
||||
HashSet<String> tokenSet = new HashSet<>();
|
||||
tokenSet.add(token);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session.cookie;
|
||||
|
||||
import cn.stylefeng.roses.kernel.auth.api.cookie.SessionCookieCreator;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
/**
|
||||
* 默认的cookie创建
|
||||
* <p>
|
||||
* 这里预留了expandCookieProp的接口可以拓展cookie的属性
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 13:29
|
||||
*/
|
||||
public class DefaultSessionCookieCreator extends SessionCookieCreator {
|
||||
|
||||
@Override
|
||||
public void expandCookieProp(Cookie cookie) {
|
||||
cookie.setHttpOnly(true);
|
||||
cookie.setPath("/");
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ 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.cookie.SessionCookieCreator;
|
||||
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordTransferEncryptApi;
|
||||
|
@ -12,6 +13,7 @@ import cn.stylefeng.roses.kernel.auth.password.RsaPasswordTransferEncrypt;
|
|||
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.cache.api.constants.CacheConstants;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -53,6 +55,17 @@ public class GunsAuthAutoConfiguration {
|
|||
return new RsaPasswordTransferEncrypt(publicKey, privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* session cookie的创建
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 15:48
|
||||
*/
|
||||
@Bean
|
||||
public SessionCookieCreator sessionCookieCreator() {
|
||||
return new DefaultSessionCookieCreator();
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的session缓存为内存缓存,方便启动
|
||||
* <p>
|
||||
|
@ -72,7 +85,7 @@ public class GunsAuthAutoConfiguration {
|
|||
MemoryLoginUserCache memoryLoginUserCache = new MemoryLoginUserCache(loginUsers);
|
||||
MemoryLoginTokenCache memoryLoginTokenCache = new MemoryLoginTokenCache(loginTokens);
|
||||
|
||||
return new DefaultSessionManager(memoryLoginUserCache, memoryLoginTokenCache, sessionExpiredSeconds);
|
||||
return new DefaultSessionManager(memoryLoginUserCache, memoryLoginTokenCache, sessionExpiredSeconds, sessionCookieCreator());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,59 +8,10 @@ package cn.stylefeng.roses.kernel.system.constants;
|
|||
*/
|
||||
public interface SymbolConstant {
|
||||
|
||||
String PERIOD = ".";
|
||||
|
||||
String COMMA = ",";
|
||||
|
||||
String COLON = ":";
|
||||
|
||||
String SEMICOLON = ";";
|
||||
|
||||
String EXCLAMATION_MARK = "!";
|
||||
|
||||
String QUESTION_MARK = "?";
|
||||
|
||||
String HYPHEN = "-";
|
||||
|
||||
String ASTERISK = "*";
|
||||
|
||||
String APOSTROPHE = "`";
|
||||
|
||||
String DASH = "-";
|
||||
|
||||
String UNDER_SCORE = "_";
|
||||
|
||||
String SINGLE_QUOTATION_MARK = "'";
|
||||
|
||||
String DOUBLE_QUOTATION_MARK = "\"";
|
||||
|
||||
String LEFT_ROUND_BRACKETS = "(";
|
||||
|
||||
String RIGHT_ROUND_BRACKETS = ")";
|
||||
|
||||
String LEFT_SQUARE_BRACKETS = "[";
|
||||
|
||||
String RIGHT_SQUARE_BRACKETS = "]";
|
||||
|
||||
String LEFT_ANGLE_BRACKETS = "<";
|
||||
|
||||
String RIGHT_ANGLE_BRACKETS = ">";
|
||||
|
||||
String LEFT_CURLY_BRACKETS = "{";
|
||||
|
||||
String RIGHT_CURLY_BRACKETS = "}";
|
||||
|
||||
String DOLLAR = "$";
|
||||
|
||||
String PERCENT = "%";
|
||||
|
||||
String LEFT_DIVIDE = "/";
|
||||
|
||||
String RIGHT_DIVIDE = "\\";
|
||||
|
||||
String LEFT_DOUBLE_DIVIDE = "//";
|
||||
|
||||
String RIGHT_DOUBLE_DIVIDE = "\\\\";
|
||||
|
||||
String EQUAL = "=";
|
||||
}
|
||||
|
|
|
@ -33,4 +33,19 @@ public interface SystemConstants {
|
|||
*/
|
||||
String PID_RIGHT_DIVIDE_SYMBOL = "]";
|
||||
|
||||
/**
|
||||
* 默认的系统版本号
|
||||
*/
|
||||
String DEFAULT_SYSTEM_VERSION = "20210101";
|
||||
|
||||
/**
|
||||
* 默认多租户的开关:关闭
|
||||
*/
|
||||
Boolean DEFAULT_TENANT_OPEN = false;
|
||||
|
||||
/**
|
||||
* 默认验证码的开关:关闭
|
||||
*/
|
||||
Boolean DEFAULT_CAPTCHA_OPEN = false;
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package cn.stylefeng.roses.kernel.system.expander;
|
||||
|
||||
import cn.stylefeng.roses.kernel.config.api.context.ConfigContext;
|
||||
import cn.stylefeng.roses.kernel.system.constants.SystemConstants;
|
||||
|
||||
/**
|
||||
* 系统的一些基础信息
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 17:13
|
||||
*/
|
||||
public class SystemConfigExpander {
|
||||
|
||||
/**
|
||||
* 获取系统发布的版本号(防止css和js的缓存)
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 17:14
|
||||
*/
|
||||
public static String getReleaseVersion() {
|
||||
return ConfigContext.me().getSysConfigValueWithDefault("SYS_RELEASE_VERSION", String.class, SystemConstants.DEFAULT_SYSTEM_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取租户是否开启的标识,默认是关的
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 17:21
|
||||
*/
|
||||
public static Boolean getTenantOpen() {
|
||||
return ConfigContext.me().getSysConfigValueWithDefault("SYS_TENANT_OPEN", Boolean.class, SystemConstants.DEFAULT_TENANT_OPEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码的开关
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/27 17:22
|
||||
*/
|
||||
public static Boolean getCaptchaOpen() {
|
||||
return ConfigContext.me().getSysConfigValueWithDefault("SYS_CAPTCHA_OPEN", Boolean.class, SystemConstants.DEFAULT_CAPTCHA_OPEN);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue