细化未登录异常类型、Cookie操作改为接口代理模式等功能点,为 v1.5.0 版本做准备

This commit is contained in:
shengzhang
2020-12-14 01:34:11 +08:00
parent 81dbf3394b
commit ee59f1a2a2
20 changed files with 748 additions and 145 deletions

View File

@@ -1,9 +1,13 @@
package cn.dev33.satoken;
import cn.dev33.satoken.action.SaTokenAction;
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.cookie.SaCookieOper;
import cn.dev33.satoken.cookie.SaCookieOperDefaultImpl;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoDefault;
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
import cn.dev33.satoken.util.SaTokenInsideUtil;
@@ -38,7 +42,6 @@ public class SaTokenManager {
}
}
/**
* 持久化 Bean
*/
@@ -54,11 +57,10 @@ public class SaTokenManager {
}
public synchronized static void initDao() {
if (dao == null) {
setDao(new SaTokenDaoDefault());
setDao(new SaTokenDaoDefaultImpl());
}
}
/**
* 权限认证 Bean
*/
@@ -78,6 +80,45 @@ public class SaTokenManager {
}
}
/**
* sa-token行为 Bean
*/
public static SaTokenAction sta;
public static SaTokenAction getSta() {
if (sta == null) {
initSta();
}
return sta;
}
public static void setSta(SaTokenAction sta) {
SaTokenManager.sta = sta;
}
public synchronized static void initSta() {
if (sta == null) {
setSta(new SaTokenActionDefaultImpl());
}
}
/**
* sa-token cookie操作 Bean
*/
public static SaCookieOper saCookieOper;
public static SaCookieOper getSaCookieOper() {
if (saCookieOper == null) {
initgetSaCookieOper();
}
return saCookieOper;
}
public static void setSaCookieOper(SaCookieOper saCookieOper) {
SaTokenManager.saCookieOper = saCookieOper;
}
public synchronized static void initgetSaCookieOper() {
if (saCookieOper == null) {
setSaCookieOper(new SaCookieOperDefaultImpl());
}
}

View File

@@ -0,0 +1,30 @@
package cn.dev33.satoken.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface SaTokenAction {
/**
* 获取当前请求的Request对象
* @return 当前请求的Request对象
*/
public HttpServletRequest getCurrRequest();
/**
* 获取当前会话的 response
* @return
*/
public HttpServletResponse getResponse();
/**
* 生成一个token
* @param loginId 账号id
* @param loginKey 登录标识key
* @return
*/
public String createToken(Object loginId, String loginKey);
}

View File

@@ -0,0 +1,47 @@
package cn.dev33.satoken.action;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.util.SpringMvcUtil;
/**
* 对 SaTokenAction 接口的默认实现
* @author kong
*
*/
public class SaTokenActionDefaultImpl implements SaTokenAction {
/**
* 获取当前请求的Request对象
*/
@Override
public HttpServletRequest getCurrRequest() {
return SpringMvcUtil.getRequest();
}
/**
* 获取当前请求的Response对象
*/
@Override
public HttpServletResponse getResponse() {
return SpringMvcUtil.getResponse();
}
/**
* 生成一个token
*/
@Override
public String createToken(Object loginId, String loginKey) {
return UUID.randomUUID().toString();
}
}

View File

@@ -0,0 +1,53 @@
package cn.dev33.satoken.cookie;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* sa-token 对cookie的相关操作 接口类
* @author kong
*
*/
public interface SaCookieOper {
/**
* 获取指定cookie .
*
* @param request .
* @param cookieName .
* @return .
*/
public Cookie getCookie(HttpServletRequest request, String cookieName);
/**
* 添加cookie
*
* @param response .
* @param name .
* @param value .
* @param path .
* @param timeout .
*/
public void addCookie(HttpServletResponse response, String name, String value, String path, int timeout);
/**
* 删除cookie .
*
* @param request .
* @param response .
* @param name .
*/
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name);
/**
* 修改cookie的value值
*
* @param request .
* @param response .
* @param name .
* @param value .
*/
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value);
}

View File

@@ -0,0 +1,44 @@
package cn.dev33.satoken.cookie;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.util.SaCookieUtil;
/**
* sa-token 对cookie的相关操作 接口实现类
* @author kong
*
*/
public class SaCookieOperDefaultImpl implements SaCookieOper {
/**
* 获取指定cookie
*/
public Cookie getCookie(HttpServletRequest request, String cookieName) {
return SaCookieUtil.getCookie(request, cookieName);
}
/**
* 添加cookie
*/
public void addCookie(HttpServletResponse response, String name, String value, String path, int timeout) {
SaCookieUtil.addCookie(response, name, value, path, timeout);
}
/**
* 删除cookie
*/
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
SaCookieUtil.delCookie(request, response, name);
}
/**
* 修改cookie的value值
*/
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value) {
SaCookieUtil.updateCookie(request, response, name, value);
}
}

View File

@@ -25,6 +25,13 @@ public interface SaTokenDao {
*/
public void setValue(String key, String value, long timeout);
/**
* 修改指定key-value键值对 (过期时间取原来的值)
* @param key 键名称
* @param value 值
*/
public void updateValue(String key, String value);
/**
* 删除一个指定的key
* @param key 键名称
@@ -57,7 +64,7 @@ public interface SaTokenDao {
* 删除一个指定的session
* @param sessionId sessionId
*/
public void delSaSession(String sessionId);
public void deleteSaSession(String sessionId);
}

View File

@@ -10,7 +10,7 @@ import cn.dev33.satoken.session.SaSession;
* @author kong
*
*/
public class SaTokenDaoDefault implements SaTokenDao {
public class SaTokenDaoDefaultImpl implements SaTokenDao {
/**
* 所有数据集合
@@ -28,6 +28,11 @@ public class SaTokenDaoDefault implements SaTokenDao {
dataMap.put(key, value);
}
@Override
public void updateValue(String key, String value) {
this.setValue(key, value, 0);
}
@Override
public void delKey(String key) {
dataMap.remove(key);
@@ -50,7 +55,7 @@ public class SaTokenDaoDefault implements SaTokenDao {
}
@Override
public void delSaSession(String sessionId) {
public void deleteSaSession(String sessionId) {
dataMap.remove(sessionId);
}

View File

@@ -1,6 +1,7 @@
package cn.dev33.satoken.exception;
import cn.dev33.satoken.stp.StpUtil;
import java.util.Arrays;
import java.util.List;
/**
* 没有登陆抛出的异常
@@ -14,35 +15,76 @@ public class NotLoginException extends RuntimeException {
*/
private static final long serialVersionUID = 6806129545290130142L;
// ------------------- 异常类型常量 --------------------
/*
* 这里简述一下为什么要把常量设计为String类型
* 因为loginId刚取出的时候类型为String为了避免两者相比较时不必要的类型转换带来的性能消耗故在此直接将常量类型设计为String
*/
/** 表示未提供token */
public static final String NOT_TOKEN = "-1";
/** 表示token无效 */
public static final String INVALID_TOKEN = "-2";
/** 表示token已被顶下线 */
public static final String BE_REPLACED = "-3";
/** 表示token已过期 */
public static final String TOKEN_TIMEOUT = "-4";
/**
* 代表异常token的标志集合
*/
public static final List<String> ABNORMAL_LIST = Arrays.asList(NOT_TOKEN, INVALID_TOKEN, BE_REPLACED, TOKEN_TIMEOUT);
/**
* login_key
* 异常类型
*/
private String type;
/**
* 获取异常类型
* @return
*/
public String getType() {
return type;
}
/**
* loginKey
*/
private String loginKey;
/**
* 获得login_key
* 获得loginKey
* @return login_key
*/
public String getLoginKey() {
return loginKey;
}
/**
* 创建一个
*/
public NotLoginException() {
this(StpUtil.stpLogic.loginKey);
}
// /**
// * 创建一个
// */
// public NotLoginException() {
// this(StpUtil.stpLogic.loginKey);
// }
/**
* 创建一个
* @param loginKey login_key
*/
public NotLoginException(String loginKey) {
public NotLoginException(String loginKey, String type) {
// 这里到底要不要拼接上login_key呢纠结
super("当前会话未登录");
this.loginKey = loginKey;
this.type = type;
}
}

View File

@@ -53,8 +53,8 @@ public class SaSessionCustomUtil {
* 删除指定key的session
* @param sessionId 删除指定key
*/
public static void delSessionById(String sessionId) {
SaTokenManager.getDao().delSaSession(getSessionKey(sessionId));
public static void deleteSessionById(String sessionId) {
SaTokenManager.getDao().deleteSaSession(getSessionKey(sessionId));
}

View File

@@ -3,7 +3,6 @@ package cn.dev33.satoken.stp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
@@ -14,9 +13,7 @@ import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.util.SaCookieUtil;
import cn.dev33.satoken.util.SaTokenInsideUtil;
import cn.dev33.satoken.util.SpringMvcUtil;
/**
* sa-token 权限验证,逻辑 实现类
@@ -42,13 +39,20 @@ public class StpLogic {
// =================== 获取token 相关 ===================
/**
* 返回token名称
* @return 此StpLogic的token名称
*/
public String getTokenName() {
return getKeyTokenName();
}
/**
* 随机生成一个tokenValue
* @return 生成的tokenValue
*/
public String randomTokenValue() {
return UUID.randomUUID().toString();
public String randomTokenValue(Object loginId) {
return SaTokenManager.getSta().createToken(loginId, loginKey);
}
/**
@@ -57,9 +61,9 @@ public class StpLogic {
*/
public String getTokenValue(){
// 0、获取相应对象
HttpServletRequest request = SpringMvcUtil.getRequest();
HttpServletRequest request = SaTokenManager.getSta().getCurrRequest();
SaTokenConfig config = SaTokenManager.getConfig();
String keyTokenName = getKeyTokenName();
String keyTokenName = getTokenName();
// 1、尝试从request里读取
if(request.getAttribute(SaTokenInsideUtil.JUST_CREATED_SAVE_KEY) != null) {
@@ -81,7 +85,7 @@ public class StpLogic {
}
// 4、尝试从cookie里读取
if(config.getIsReadCookie() == true){
Cookie cookie = SaCookieUtil.getCookie(request, keyTokenName);
Cookie cookie = SaTokenManager.getSaCookieOper().getCookie(request, keyTokenName);
if(cookie != null){
String tokenValue = cookie.getValue();
if(tokenValue != null) {
@@ -108,7 +112,7 @@ public class StpLogic {
*/
public Map<String, String> getTokenInfo() {
Map<String, String> map = new HashMap<String, String>();
map.put("tokenName", getKeyTokenName());
map.put("tokenName", getTokenName());
map.put("tokenValue", getTokenValue());
return map;
}
@@ -123,19 +127,20 @@ public class StpLogic {
public void setLoginId(Object loginId) {
// 1、获取相应对象
HttpServletRequest request = SpringMvcUtil.getRequest();
HttpServletRequest request = SaTokenManager.getSta().getCurrRequest();
SaTokenConfig config = SaTokenManager.getConfig();
SaTokenDao dao = SaTokenManager.getDao();
// 2、获取tokenValue
String tokenValue = getTokenValueByLoginId(loginId); // 获取旧tokenValue
if(tokenValue == null){ // 为null则创建一个新的
tokenValue = randomTokenValue();
tokenValue = randomTokenValue(loginId);
} else {
// 不为null, 并且配置不共享,则删掉原来,并且创建新的
// 不为null, 并且配置不共享,则:将原来的标记为[被顶替]
if(config.getIsShare() == false){
dao.delKey(getKeyTokenValue(tokenValue));
tokenValue = randomTokenValue();
// dao.delKey(getKeyTokenValue(tokenValue));
dao.updateValue(getKeyTokenValue(tokenValue), NotLoginException.BE_REPLACED);
tokenValue = randomTokenValue(loginId);
}
}
@@ -144,7 +149,7 @@ public class StpLogic {
dao.setValue(getKeyLoginId(loginId), tokenValue, config.getTimeout()); // uid -> token
request.setAttribute(SaTokenInsideUtil.JUST_CREATED_SAVE_KEY, tokenValue); // 保存到本次request里
if(config.getIsReadCookie() == true){
SaCookieUtil.addCookie(SpringMvcUtil.getResponse(), getKeyTokenName(), tokenValue, "/", (int)config.getTimeout()); // cookie注入
SaTokenManager.getSaCookieOper().addCookie(SaTokenManager.getSta().getResponse(), getTokenName(), tokenValue, "/", (int)config.getTimeout()); // cookie注入
}
}
@@ -152,14 +157,27 @@ public class StpLogic {
* 当前会话注销登录
*/
public void logout() {
Object loginId = getLoginIdDefaultNull();
if(loginId != null) {
logoutByLoginId(loginId);
// 清除cookie
if(SaTokenManager.getConfig().getIsReadCookie() == true){
SaCookieUtil.delCookie(SpringMvcUtil.getRequest(), SpringMvcUtil.getResponse(), getKeyTokenName());
}
// 如果连token都没有那么无需执行任何操作
String tokenValue = getTokenValue();
if(tokenValue == null) {
return;
}
// 如果打开了cookie模式第一步先把cookie清除掉
if(SaTokenManager.getConfig().getIsReadCookie() == true){
SaTokenManager.getSaCookieOper().delCookie(SaTokenManager.getSta().getCurrRequest(), SaTokenManager.getSta().getResponse(), getTokenName());
}
// 尝试从db中获取loginId值
String loginId = SaTokenManager.getDao().getValue(getKeyTokenValue(tokenValue));
// 如果根本查不到loginId那么也无需执行任何操作
if(loginId == null) {
return;
}
// 如果已经被顶替或已过期那么只删除此token即可
if(loginId.equals(NotLoginException.BE_REPLACED) || loginId.equals(NotLoginException.TOKEN_TIMEOUT)) {
return;
}
// 至此已经是一个正常的loginId开始三清
logoutByLoginId(loginId);
}
/**
@@ -178,7 +196,6 @@ public class StpLogic {
SaTokenManager.getDao().delKey(getKeyTokenValue(tokenValue)); // 清除token-id键值对
SaTokenManager.getDao().delKey(getKeyLoginId(loginId)); // 清除id-token键值对
SaTokenManager.getDao().delKey(getKeySession(loginId)); // 清除其session
// SaCookieUtil.delCookie(SpringMVCUtil.getRequest(), SpringMVCUtil.getResponse(), getKey_tokenName()); // 清除cookie
}
// 查询相关
@@ -188,6 +205,7 @@ public class StpLogic {
* @return 是否已登录
*/
public boolean isLogin() {
// 判断条件不为null并且不在异常项集合里
return getLoginIdDefaultNull() != null;
}
@@ -203,10 +221,25 @@ public class StpLogic {
* @return .
*/
public Object getLoginId() {
Object loginId = getLoginIdDefaultNull();
if(loginId == null) {
throw new NotLoginException(this.loginKey);
// 如果获取不到token则抛出无token
String tokenValue = getTokenValue();
if(tokenValue == null) {
throw new NotLoginException(loginKey, NotLoginException.NOT_TOKEN);
}
// 查找此token对应loginId, 则抛出无效token
String loginId = SaTokenManager.getDao().getValue(getKeyTokenValue(tokenValue));
if(loginId == null) {
throw new NotLoginException(loginKey, NotLoginException.INVALID_TOKEN);
}
// 如果是已经被顶替下去了, 则抛出:已被顶下线
if(loginId.equals(NotLoginException.BE_REPLACED)) {
throw new NotLoginException(loginKey, NotLoginException.BE_REPLACED);
}
// 如果是已经过期,则抛出已经过期
if(loginId.equals(NotLoginException.TOKEN_TIMEOUT)) {
throw new NotLoginException(loginKey, NotLoginException.TOKEN_TIMEOUT);
}
// 至此返回loginId
return loginId;
}
@@ -218,9 +251,11 @@ public class StpLogic {
@SuppressWarnings("unchecked")
public <T>T getLoginId(T defaultValue) {
Object loginId = getLoginIdDefaultNull();
// 如果loginId为null则返回默认值
if(loginId == null) {
return defaultValue;
}
// 开始尝试类型转换只尝试三种类型int、long、String
if(defaultValue instanceof Integer) {
return (T)Integer.valueOf(loginId.toString());
}
@@ -235,17 +270,21 @@ public class StpLogic {
/**
* 获取当前会话登录id, 如果未登录则返回null
* @return
* @return .
*/
public Object getLoginIdDefaultNull() {
String tokenValue = getTokenValue();
if(tokenValue != null) {
Object loginId = SaTokenManager.getDao().getValue(getKeyTokenValue(tokenValue));
if(loginId != null) {
return loginId;
}
// 如果连token都是空的则直接返回
String tokenValue = getTokenValue();
if(tokenValue == null) {
return null;
}
return null;
// loginId为null或者在异常项里面均视为未登录
Object loginId = SaTokenManager.getDao().getValue(getKeyTokenValue(tokenValue));
if(loginId == null || NotLoginException.ABNORMAL_LIST.contains(loginId)) {
return null;
}
// 执行到此证明loginId已经是个正常的账号id了
return loginId;
}
/**
@@ -328,7 +367,7 @@ public class StpLogic {
* @return .
*/
public SaSession getSessionByLoginId(Object loginId) {
return getSessionByLoginId(getKeySession(loginId), false);
return getSessionByLoginId(loginId, true);
}
/**
@@ -336,7 +375,7 @@ public class StpLogic {
* @return
*/
public SaSession getSession() {
return getSessionBySessionId(getKeySession(getLoginId()), true);
return getSessionByLoginId(getLoginId());
}

View File

@@ -21,6 +21,13 @@ public class StpUtil {
// =================== 获取token 相关 ===================
/**
* 返回token名称
* @return 此StpLogic的token名称
*/
public static String getTokenName() {
return stpLogic.getTokenName();
}
/**
* 获取当前tokenValue

View File

@@ -4,92 +4,90 @@ import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* cookie工具类
* cookie操作工具类
*
* @author kong
*
*/
public class SaCookieUtil {
/**
* 获取指定cookie .
* @param request .
*
* @param request .
* @param cookieName .
* @return .
*/
public static Cookie getCookie(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for(int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if(cookie != null && cookieName.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
public static Cookie getCookie(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && cookieName.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
/**
* 添加cookie
*
* @param response .
* @param name .
* @param value .
* @param path .
* @param timeout .
*/
public static void addCookie(HttpServletResponse response, String name, String value, String path, int timeout) {
Cookie cookie = new Cookie(name, value);
if (path == null) {
path = "/";
}
cookie.setPath(path);
cookie.setMaxAge(timeout);
response.addCookie(cookie);
}
/**
* 添加cookie
* @param response .
* @param name .
* @param value .
* @param path .
* @param timeout .
*/
public static void addCookie(HttpServletResponse response,String name,String value,String path,int timeout) {
Cookie cookie = new Cookie(name, value);
if(path == null) {
path = "/";
}
cookie.setPath(path);
cookie.setMaxAge(timeout);
response.addCookie(cookie);
}
/**
* 删除cookie .
*
* @param request .
* @param response .
* @param name .
*/
public static void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && (name).equals(cookie.getName())) {
addCookie(response, name, null, null, 0);
return;
}
}
}
}
/**
* 修改cookie的value值
*
* @param request .
* @param response .
* @param name .
* @param value .
*/
public static void updateCookie(HttpServletRequest request, HttpServletResponse response, String name,
String value) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && (name).equals(cookie.getName())) {
addCookie(response, name, value, cookie.getPath(), cookie.getMaxAge());
return;
}
}
}
}
/**
* 删除cookie .
* @param request .
* @param response .
* @param name .
*/
public static void delCookie(HttpServletRequest request,HttpServletResponse response,String name) {
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies) {
if(cookies != null && (name).equals(cookie.getName())) {
addCookie(response,name,null,null,0);
return;
}
}
}
}
/**
* 修改cookie的value值
* @param request .
* @param response .
* @param name .
* @param value .
*/
public static void updateCookie(HttpServletRequest request,HttpServletResponse response,String name,String value) {
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies) {
if(cookies != null && (name).equals(cookie.getName())) {
addCookie(response,name,value,cookie.getPath(),cookie.getMaxAge());
return;
}
}
}
}
}