diff --git a/sa-token-demo-springboot/pom.xml b/sa-token-demo-springboot/pom.xml index bb6dc0c2..e59c0d06 100644 --- a/sa-token-demo-springboot/pom.xml +++ b/sa-token-demo-springboot/pom.xml @@ -26,18 +26,18 @@ - + - + diff --git a/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java b/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java index 1273ceb0..436eaea0 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/SaTokenDemoApplication.java @@ -13,6 +13,7 @@ public class SaTokenDemoApplication { public static void main(String[] args) { SpringApplication.run(SaTokenDemoApplication.class, args); System.out.println("启动成功:sa-token配置如下:" + SaTokenManager.getConfig()); +// StpUtil.getSessionByLoginId(10001) } diff --git a/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java b/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java index 4e8b861d..ec32e9d5 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/satoken/MySaTokenConfig.java @@ -15,7 +15,7 @@ import cn.dev33.satoken.config.SaTokenConfig; @Configuration public class MySaTokenConfig implements WebMvcConfigurer { - // 获取配置Bean (以代码的方式配置sa-token) + // 获取配置Bean (以代码的方式配置sa-token, 此配置会覆盖yml中的配置 ) @Primary @Bean(name="MySaTokenConfig") public SaTokenConfig getSaTokenConfig() { diff --git a/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java b/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java index bc88aa85..4c0c44ae 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenDaoRedis.java @@ -7,7 +7,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; -// import org.springframework.stereotype.Component; +import org.springframework.stereotype.Component; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.session.SaSession; @@ -15,7 +15,7 @@ import cn.dev33.satoken.session.SaSession; /** * sa-token持久层的实现类 , 基于redis */ -// @Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成 +@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成 public class SaTokenDaoRedis implements SaTokenDao { @@ -46,6 +46,16 @@ public class SaTokenDaoRedis implements SaTokenDao { stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); } + // 更新指定key-value键值对 (过期时间取原来的值) + @Override + public void updateValue(String key, String value) { + long expire = redisTemplate.getExpire(key); + if(expire == -2) { // -2 = 无此键 + return; + } + stringRedisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); + } + // 删除一个指定的key @Override public void delKey(String key) { @@ -77,10 +87,13 @@ public class SaTokenDaoRedis implements SaTokenDao { // 删除一个指定的session @Override - public void delSaSession(String sessionId) { + public void deleteSaSession(String sessionId) { redisTemplate.delete(sessionId); } + + + diff --git a/sa-token-demo-springboot/src/main/java/com/pj/satoken/StpUserUtil.java b/sa-token-demo-springboot/src/main/java/com/pj/satoken/StpUserUtil.java new file mode 100644 index 00000000..537a614a --- /dev/null +++ b/sa-token-demo-springboot/src/main/java/com/pj/satoken/StpUserUtil.java @@ -0,0 +1,238 @@ +package com.pj.satoken; + +import java.util.Map; + +import org.springframework.stereotype.Service; + +import cn.dev33.satoken.SaTokenManager; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpLogic; + +/** + * 一个默认的实现 + * @author kong + */ +@Service +public class StpUserUtil { + + /** + * 底层的 StpLogic 对象 + */ + public static StpLogic stpLogic = new StpLogic("user") { + @Override + public String getKeyTokenName() { + return SaTokenManager.getConfig().getTokenName() + "-user"; + } + }; + + + // =================== 获取token 相关 =================== + + /** + * 返回token名称 + * @return 此StpLogic的token名称 + */ + public static String getTokenName() { + return stpLogic.getTokenName(); + } + + /** + * 获取当前tokenValue + * @return 当前tokenValue + */ + public static String getTokenValue() { + return stpLogic.getTokenValue(); + } + + /** + * 获取指定id的tokenValue + * @param loginId . + * @return + */ + public static String getTokenValueByLoginId(Object loginId) { + return stpLogic.getTokenValueByLoginId(loginId); + } + + /** + * 获取当前会话的token信息:tokenName与tokenValue + * @return 一个Map对象 + */ + public static Map getTokenInfo() { + return stpLogic.getTokenInfo(); + } + + // =================== 登录相关操作 =================== + + /** + * 在当前会话上登录id + * @param loginId 登录id ,建议的类型:(long | int | String) + */ + public static void setLoginId(Object loginId) { + stpLogic.setLoginId(loginId); + } + + /** + * 当前会话注销登录 + */ + public static void logout() { + stpLogic.logout(); + } + + /** + * 指定loginId的会话注销登录(踢人下线) + * @param loginId 账号id + */ + public static void logoutByLoginId(Object loginId) { + stpLogic.logoutByLoginId(loginId); + } + + // 查询相关 + + /** + * 获取当前会话是否已经登录 + * @return 是否已登录 + */ + public static boolean isLogin() { + return stpLogic.isLogin(); + } + + /** + * 检验当前会话是否已经登录,如未登录,则抛出异常 + */ + public static void checkLogin() { + getLoginId(); + } + + /** + * 获取当前会话登录id, 如果未登录,则抛出异常 + * @return . + */ + public static Object getLoginId() { + return stpLogic.getLoginId(); + } + + /** + * 获取当前会话登录id, 如果未登录,则返回默认值 + * @param defaultValue . + * @return . + */ + public static T getLoginId(T defaultValue) { + return stpLogic.getLoginId(defaultValue); + } + + /** + * 获取当前会话登录id, 如果未登录,则返回null + * @return + */ + public static Object getLoginIdDefaultNull() { + return stpLogic.getLoginIdDefaultNull(); + } + + /** + * 获取当前会话登录id, 并转换为String + * @return + */ + public static String getLoginIdAsString() { + return stpLogic.getLoginIdAsString(); + } + + /** + * 获取当前会话登录id, 并转换为int + * @return + */ + public static int getLoginIdAsInt() { + return stpLogic.getLoginIdAsInt(); + } + + /** + * 获取当前会话登录id, 并转换为long + * @return + */ + public static long getLoginIdAsLong() { + return stpLogic.getLoginIdAsLong(); + } + + /** + * 获取指定token对应的登录id,如果未登录,则返回 null + * @return . + */ + public static Object getLoginIdByToken(String tokenValue) { + return stpLogic.getLoginIdByToken(tokenValue); + } + + // =================== session相关 =================== + + /** + * 获取指定loginId的session, 如果没有,isCreate=是否新建并返回 + * @param loginId 登录id + * @param isCreate 是否新建 + * @return SaSession + */ + public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) { + return stpLogic.getSessionByLoginId(loginId, isCreate); + } + + /** + * 获取指定loginId的session + * @param loginId . + * @return . + */ + public static SaSession getSessionByLoginId(Object loginId) { + return stpLogic.getSessionByLoginId(loginId); + } + + /** + * 获取当前会话的session + * @return + */ + public static SaSession getSession() { + return stpLogic.getSession(); + } + + // =================== 权限验证操作 =================== + + /** + * 指定loginId是否含有指定权限 + * @param loginId . + * @param pcode . + * @return . + */ + public static boolean hasPermission(Object loginId, Object pcode) { + return stpLogic.hasPermission(loginId, pcode); + } + + /** + * 当前会话是否含有指定权限 + * @param pcode . + * @return . + */ + public static boolean hasPermission(Object pcode) { + return stpLogic.hasPermission(pcode); + } + + /** + * 当前账号是否含有指定权限 , 没有就抛出异常 + * @param pcode . + */ + public static void checkPermission(Object pcode) { + stpLogic.checkPermission(pcode); + } + + /** + * 当前账号是否含有指定权限 , 【指定多个,必须全都有】 + * @param pcodeArray . + */ + public static void checkPermissionAnd(Object... pcodeArray) { + stpLogic.checkPermissionAnd(pcodeArray); + } + + /** + * 当前账号是否含有指定权限 , 【指定多个,有一个就可以了】 + * @param pcodeArray . + */ + public static void checkPermissionOr(Object... pcodeArray) { + stpLogic.checkPermissionOr(pcodeArray); + } + + +} diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java b/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java index f26f1cf8..b60317e0 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/GlobalException.java @@ -36,6 +36,20 @@ public class GlobalException { AjaxJson aj = null; if (e instanceof NotLoginException) { // 如果是未登录异常 aj = AjaxJson.getNotLogin(); + // 判断具体是什么类型 + NotLoginException ee = (NotLoginException) e; + if(ee.getType() == NotLoginException.NOT_TOKEN) { + aj.setMsg("未提供token"); + } + if(ee.getType() == NotLoginException.INVALID_TOKEN) { + aj.setMsg("token无效"); + } + if(ee.getType() == NotLoginException.BE_REPLACED) { + aj.setMsg("token已被顶下线"); + } + if(ee.getType() == NotLoginException.TOKEN_TIMEOUT) { + aj.setMsg("token已过期"); + } } else if(e instanceof NotPermissionException) { // 如果是权限异常 NotPermissionException ee = (NotPermissionException) e; aj = AjaxJson.getNotJur("无此权限:" + ee.getCode()); diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index f5fc23dd..0c84a93e 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -112,10 +112,29 @@ public class TestController { return AjaxJson.getSuccess(); } + // 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/getInfo @SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过 @RequestMapping("getInfo") public AjaxJson getInfo() { return AjaxJson.getSuccessData("用户信息"); } + + + // 测试 浏览器访问: http://localhost:8081/test/test + @RequestMapping("test") + public AjaxJson test() { + StpUtil.setLoginId(10001); + +// System.out.println(StpUtil.getSession().getId()); +// System.out.println(StpUserUtil.getSession().getId()); + StpUtil.getSessionByLoginId(10001).setAttribute("name", "123"); + System.out.println(StpUtil.getSessionByLoginId(10001).getAttribute("name")); + + return AjaxJson.getSuccess(); + } + + + + } diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/SaTokenManager.java b/sa-token-dev/src/main/java/cn/dev33/satoken/SaTokenManager.java index f6b30af3..380c3116 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/SaTokenManager.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/SaTokenManager.java @@ -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()); + } + } + + diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/action/SaTokenAction.java b/sa-token-dev/src/main/java/cn/dev33/satoken/action/SaTokenAction.java new file mode 100644 index 00000000..da24f4ef --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/action/SaTokenAction.java @@ -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); + + +} diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/action/SaTokenActionDefaultImpl.java b/sa-token-dev/src/main/java/cn/dev33/satoken/action/SaTokenActionDefaultImpl.java new file mode 100644 index 00000000..98c742f8 --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/action/SaTokenActionDefaultImpl.java @@ -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(); + } + + + + + +} diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/cookie/SaCookieOper.java b/sa-token-dev/src/main/java/cn/dev33/satoken/cookie/SaCookieOper.java new file mode 100644 index 00000000..bc6c82c0 --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/cookie/SaCookieOper.java @@ -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); + +} diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/cookie/SaCookieOperDefaultImpl.java b/sa-token-dev/src/main/java/cn/dev33/satoken/cookie/SaCookieOperDefaultImpl.java new file mode 100644 index 00000000..a5d2e09b --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/cookie/SaCookieOperDefaultImpl.java @@ -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); + } + +} diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java b/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java index aa6408cb..2de1ce57 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java @@ -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); } diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefault.java b/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java similarity index 81% rename from sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefault.java rename to sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java index 72706f8a..a1a45cdc 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefault.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java @@ -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); } diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/exception/NotLoginException.java b/sa-token-dev/src/main/java/cn/dev33/satoken/exception/NotLoginException.java index e35cedd2..ac25813b 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/exception/NotLoginException.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/exception/NotLoginException.java @@ -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 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; } } diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java b/sa-token-dev/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java index 2055753e..a6e9b30e 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/session/SaSessionCustomUtil.java @@ -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)); } diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 9abba608..37f847bc 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -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 getTokenInfo() { Map map = new HashMap(); - 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 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()); } diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 71a9864b..9933e70e 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -21,6 +21,13 @@ public class StpUtil { // =================== 获取token 相关 =================== + /** + * 返回token名称 + * @return 此StpLogic的token名称 + */ + public static String getTokenName() { + return stpLogic.getTokenName(); + } /** * 获取当前tokenValue diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/util/SaCookieUtil.java b/sa-token-dev/src/main/java/cn/dev33/satoken/util/SaCookieUtil.java index ab850f24..7946a0ae 100644 --- a/sa-token-dev/src/main/java/cn/dev33/satoken/util/SaCookieUtil.java +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/util/SaCookieUtil.java @@ -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; - } - } - } - } - - - } \ No newline at end of file diff --git a/sa-token-doc/doc/use/dao-extend.md b/sa-token-doc/doc/use/dao-extend.md index 7a4e1fcf..99754993 100644 --- a/sa-token-doc/doc/use/dao-extend.md +++ b/sa-token-doc/doc/use/dao-extend.md @@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; -import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.stereotype.Component; @@ -29,7 +28,7 @@ import cn.dev33.satoken.session.SaSession; /** * sa-token持久层的实现类 , 基于redis */ -@Component // 保证此类被springboot扫描,即可完成sa-token与redis的集成 +@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成 public class SaTokenDaoRedis implements SaTokenDao { @@ -42,10 +41,8 @@ public class SaTokenDaoRedis implements SaTokenDao { @Autowired @SuppressWarnings({ "rawtypes", "unchecked" }) public void setRedisTemplate(RedisTemplate redisTemplate) { - RedisSerializer stringSerializer = new StringRedisSerializer(); - redisTemplate.setKeySerializer(stringSerializer); - JdkSerializationRedisSerializer jrSerializer = new JdkSerializationRedisSerializer(); - redisTemplate.setValueSerializer(jrSerializer); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); this.redisTemplate = redisTemplate; } @@ -62,6 +59,16 @@ public class SaTokenDaoRedis implements SaTokenDao { stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); } + // 更新指定key-value键值对 (过期时间取原来的值) + @Override + public void updateValue(String key, String value) { + long expire = redisTemplate.getExpire(key); + if(expire == -2) { // -2 = 无此键 + return; + } + stringRedisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); + } + // 删除一个指定的key @Override public void delKey(String key) { @@ -93,12 +100,10 @@ public class SaTokenDaoRedis implements SaTokenDao { // 删除一个指定的session @Override - public void delSaSession(String sessionId) { + public void deleteSaSession(String sessionId) { redisTemplate.delete(sessionId); } - - }