新增 Thymeleaf 标签方言插件

This commit is contained in:
click33 2021-10-01 22:54:56 +08:00
parent f260f6028a
commit d107b6b341
23 changed files with 723 additions and 41 deletions

View File

@ -90,6 +90,16 @@ public class SaLoginModel {
return (int)(long)timeout;
}
/**
* @return 获取device参数如果为null则返回默认值
*/
public String getDeviceOrDefalut() {
if(device == null) {
return SaTokenConsts.DEFAULT_LOGIN_DEVICE;
}
return device;
}
/**
* 构建对象初始化默认值
* @return 对象自身
@ -104,9 +114,9 @@ public class SaLoginModel {
* @return 对象自身
*/
public SaLoginModel build(SaTokenConfig config) {
if(device == null) {
device = SaTokenConsts.DEFAULT_LOGIN_DEVICE;
}
// if(device == null) {
// device = SaTokenConsts.DEFAULT_LOGIN_DEVICE;
// }
if(isLastingCookie == null) {
isLastingCookie = true;
}

View File

@ -253,7 +253,7 @@ public class StpLogic {
session.updateMinTimeout(loginModel.getTimeout());
// User-Session 上记录token签名
session.addTokenSign(tokenValue, loginModel.getDevice());
session.addTokenSign(tokenValue, loginModel.getDeviceOrDefalut());
// ------ 4. 持久化其它数据
// token -> id 映射关系
@ -974,7 +974,7 @@ public class StpLogic {
* @return 是否含有指定角色标识
*/
public boolean hasRole(String role) {
return hasRole(getLoginId(), role);
return isLogin() && hasRole(getLoginId(), role);
}
/**
@ -986,7 +986,7 @@ public class StpLogic {
try {
checkRoleAnd(roleArray);
return true;
} catch (NotRoleException e) {
} catch (NotLoginException | NotRoleException e) {
return false;
}
}
@ -1000,7 +1000,7 @@ public class StpLogic {
try {
checkRoleOr(roleArray);
return true;
} catch (NotRoleException e) {
} catch (NotLoginException | NotRoleException e) {
return false;
}
}
@ -1046,6 +1046,16 @@ public class StpLogic {
throw new NotRoleException(roleArray[0], this.loginType);
}
}
// --
/**
* 返回当前账号所拥有的角色标识集合
* @return /
*/
public List<String> getRoleList() {
return SaManager.getStpInterface().getRoleList(getLoginId(), loginType);
}
// ------------------- 权限验证操作 -------------------
@ -1067,7 +1077,7 @@ public class StpLogic {
* @return 是否含有指定权限
*/
public boolean hasPermission(String permission) {
return hasPermission(getLoginId(), permission);
return isLogin() && hasPermission(getLoginId(), permission);
}
/**
@ -1079,7 +1089,7 @@ public class StpLogic {
try {
checkPermissionAnd(permissionArray);
return true;
} catch (NotPermissionException e) {
} catch (NotLoginException | NotPermissionException e) {
return false;
}
}
@ -1093,7 +1103,7 @@ public class StpLogic {
try {
checkPermissionOr(permissionArray);
return true;
} catch (NotPermissionException e) {
} catch (NotLoginException | NotPermissionException e) {
return false;
}
}
@ -1140,10 +1150,17 @@ public class StpLogic {
}
}
// --
/**
* 返回当前账号所拥有的权限码集合
* @return /
*/
public List<String> getPermissionList() {
return SaManager.getStpInterface().getPermissionList(getLoginId(), loginType);
}
// ------------------- id 反查token 相关操作 -------------------
// ------------------- id 反查 token 相关操作 -------------------
/**
* 获取指定账号id的tokenValue
@ -1153,7 +1170,7 @@ public class StpLogic {
* @return token值
*/
public String getTokenValueByLoginId(Object loginId) {
return getTokenValueByLoginId(loginId, SaTokenConsts.DEFAULT_LOGIN_DEVICE);
return getTokenValueByLoginId(loginId, null);
}
/**
@ -1161,7 +1178,7 @@ public class StpLogic {
* <p> 在配置为允许并发登录时此方法只会返回队列的最后一个token
* 如果你需要返回此账号id的所有token请调用 getTokenValueListByLoginId
* @param loginId 账号id
* @param device 设备标识
* @param device 设备标识填null代表不限设备
* @return token值
*/
public String getTokenValueByLoginId(Object loginId, String device) {
@ -1175,13 +1192,13 @@ public class StpLogic {
* @return 此loginId的所有相关token
*/
public List<String> getTokenValueListByLoginId(Object loginId) {
return getTokenValueListByLoginId(loginId, SaTokenConsts.DEFAULT_LOGIN_DEVICE);
return getTokenValueListByLoginId(loginId, null);
}
/**
* 获取指定账号id指定设备端的tokenValue 集合
* @param loginId 账号id
* @param device 设备标识
* @param device 设备标识填null代表不限设备
* @return 此loginId的所有相关token
*/
public List<String> getTokenValueListByLoginId(Object loginId, String device) {
@ -1194,7 +1211,7 @@ public class StpLogic {
List<TokenSign> tokenSignList = session.getTokenSignList();
List<String> tokenValueList = new ArrayList<>();
for (TokenSign tokenSign : tokenSignList) {
if(tokenSign.getDevice().equals(device)) {
if(device == null || tokenSign.getDevice().equals(device)) {
tokenValueList.add(tokenSign.getValue());
}
}
@ -1267,7 +1284,7 @@ public class StpLogic {
}
// ------------------- 其它方法 -------------------
// ------------------- 注解鉴权 -------------------
/**
* 根据注解(@SaCheckLogin)鉴权

View File

@ -2,6 +2,7 @@ package cn.dev33.satoken.stp;
import java.util.List;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.session.SaSession;
@ -29,6 +30,16 @@ public class StpUtil {
return stpLogic.getLoginType();
}
/**
* 重置 StpLogic 对象
* @param stpLogic /
*/
public static void setStpLogic(StpLogic stpLogic) {
StpUtil.stpLogic = stpLogic;
// 防止自定义 stpLogic 被覆盖
SaManager.putStpLogic(stpLogic);
}
// =================== 获取token 相关 ===================
@ -446,7 +457,16 @@ public class StpUtil {
public static void checkRoleOr(String... roleArray){
stpLogic.checkRoleOr(roleArray);
}
// --
/**
* 返回当前账号所拥有的角色标识集合
* @return /
*/
public static List<String> getRoleList() {
return stpLogic.getRoleList();
}
// =================== 权限验证操作 ===================
@ -511,6 +531,15 @@ public class StpUtil {
stpLogic.checkPermissionOr(permissionArray);
}
// --
/**
* 返回当前账号所拥有的权限码集合
* @return /
*/
public static List<String> getPermissionList() {
return stpLogic.getPermissionList();
}
// =================== id 反查token 相关操作 ===================

View File

@ -404,4 +404,6 @@ public class SaFoxUtil {
return str;
}
}

View File

@ -2,11 +2,13 @@ package com.pj.satoken.at;
import java.util.List;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
/**
* Sa-Token 权限认证工具类
@ -32,6 +34,16 @@ public class StpUserUtil {
return stpLogic.getLoginType();
}
/**
* 重置 StpLogic 对象
* @param stpLogic /
*/
public static void setStpLogic(StpLogic stpLogic) {
StpUtil.stpLogic = stpLogic;
// 防止自定义 stpLogic 被覆盖
SaManager.putStpLogic(stpLogic);
}
// =================== 获取token 相关 ===================
@ -136,7 +148,7 @@ public class StpUserUtil {
}
/**
* 注销会话根据指定 Token
* 会话注销根据指定 Token
*
* @param tokenValue 指定token
*/
@ -264,7 +276,7 @@ public class StpUserUtil {
}
// =================== session相关 ===================
// =================== User-Session 相关 ===================
/**
* 获取指定账号id的Session, 如果Session尚未创建isCreate=是否新建并返回
@ -312,7 +324,7 @@ public class StpUserUtil {
}
// =================== token专属session ===================
// =================== Token-Session 相关 ===================
/**
* 获取指定Token-Session如果Session尚未创建则新建并返回
@ -354,7 +366,7 @@ public class StpUserUtil {
// =================== 过期时间相关 ===================
/**
* 获取当前登录者的token剩余有效时间 (单位: )
* 获取当前登录者的 token 剩余有效时间 (单位: )
* @return token剩余有效时间
*/
public static long getTokenTimeout() {
@ -362,7 +374,7 @@ public class StpUserUtil {
}
/**
* 获取当前登录者的Session剩余有效时间 (单位: )
* 获取当前登录者的 User-Session 剩余有效时间 (单位: )
* @return token剩余有效时间
*/
public static long getSessionTimeout() {
@ -370,7 +382,7 @@ public class StpUserUtil {
}
/**
* 获取当前token的专属Session剩余有效时间 (单位: )
* 获取当前 Token-Session 剩余有效时间 (单位: )
* @return token剩余有效时间
*/
public static long getTokenSessionTimeout() {
@ -378,8 +390,8 @@ public class StpUserUtil {
}
/**
* 获取当前token[临时过期]剩余有效时间 (单位: )
* @return token[临时过期]剩余有效时间
* 获取当前 token [临时过期] 剩余有效时间 (单位: )
* @return token [临时过期] 剩余有效时间
*/
public static long getTokenActivityTimeout() {
return stpLogic.getTokenActivityTimeout();
@ -390,7 +402,7 @@ public class StpUserUtil {
// =================== 角色验证操作 ===================
/**
* 指定账号id是否含有角色标识, 返回true或false
* 判断指定账号id是否含有角色标识, 返回true或false
* @param loginId 账号id
* @param role 角色标识
* @return 是否含有指定角色标识
@ -400,16 +412,34 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定角色标识, 返回true或false
* 判断当前账号是否含有指定角色标识, 返回true或false
* @param role 角色标识
* @return 是否含有指定角色标识
*/
public static boolean hasRole(String role) {
return stpLogic.hasRole(role);
}
/**
* 当前账号是否含有指定角色标识, 如果验证未通过则抛出异常: NotRoleException
* 判断当前账号是否含有指定角色标识 [指定多个必须全部验证通过]
* @param roleArray 角色标识数组
* @return true或false
*/
public static boolean hasRoleAnd(String... roleArray){
return stpLogic.hasRoleAnd(roleArray);
}
/**
* 判断当前账号是否含有指定角色标识 [指定多个只要其一验证通过即可]
* @param roleArray 角色标识数组
* @return true或false
*/
public static boolean hasRoleOr(String... roleArray){
return stpLogic.hasRoleOr(roleArray);
}
/**
* 校验当前账号是否含有指定角色标识, 如果验证未通过则抛出异常: NotRoleException
* @param role 角色标识
*/
public static void checkRole(String role) {
@ -417,7 +447,7 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定角色标识 [指定多个必须全部验证通过]
* 校验当前账号是否含有指定角色标识 [指定多个必须全部验证通过]
* @param roleArray 角色标识数组
*/
public static void checkRoleAnd(String... roleArray){
@ -425,18 +455,27 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定角色标识 [指定多个只要其一验证通过即可]
* 校验当前账号是否含有指定角色标识 [指定多个只要其一验证通过即可]
* @param roleArray 角色标识数组
*/
public static void checkRoleOr(String... roleArray){
stpLogic.checkRoleOr(roleArray);
}
// --
/**
* 返回当前账号所拥有的角色标识集合
* @return /
*/
public static List<String> getRoleList() {
return stpLogic.getRoleList();
}
// =================== 权限验证操作 ===================
/**
* 指定账号id是否含有指定权限, 返回true或false
* 判断指定账号id是否含有指定权限, 返回true或false
* @param loginId 账号id
* @param permission 权限码
* @return 是否含有指定权限
@ -446,7 +485,7 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定权限, 返回true或false
* 判断当前账号是否含有指定权限, 返回true或false
* @param permission 权限码
* @return 是否含有指定权限
*/
@ -455,7 +494,25 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定权限, 如果验证未通过则抛出异常: NotPermissionException
* 判断当前账号是否含有指定权限, [指定多个必须全部具有]
* @param permissionArray 权限码数组
* @return true false
*/
public static boolean hasPermissionAnd(String... permissionArray){
return stpLogic.hasPermissionAnd(permissionArray);
}
/**
* 判断当前账号是否含有指定权限 [指定多个只要其一验证通过即可]
* @param permissionArray 权限码数组
* @return true false
*/
public static boolean hasPermissionOr(String... permissionArray){
return stpLogic.hasPermissionOr(permissionArray);
}
/**
* 校验当前账号是否含有指定权限, 如果验证未通过则抛出异常: NotPermissionException
* @param permission 权限码
*/
public static void checkPermission(String permission) {
@ -463,7 +520,7 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定权限 [指定多个必须全部验证通过]
* 校验当前账号是否含有指定权限 [指定多个必须全部验证通过]
* @param permissionArray 权限码数组
*/
public static void checkPermissionAnd(String... permissionArray) {
@ -471,13 +528,22 @@ public class StpUserUtil {
}
/**
* 当前账号是否含有指定权限 [指定多个只要其一验证通过即可]
* 校验当前账号是否含有指定权限 [指定多个只要其一验证通过即可]
* @param permissionArray 权限码数组
*/
public static void checkPermissionOr(String... permissionArray) {
stpLogic.checkPermissionOr(permissionArray);
}
// --
/**
* 返回当前账号所拥有的权限码集合
* @return /
*/
public static List<String> getPermissionList() {
return stpLogic.getPermissionList();
}
// =================== id 反查token 相关操作 ===================
@ -687,6 +753,7 @@ public class StpUserUtil {
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.getLoginType() 使用方式保持不变 </h1>
*
* 获取当前StpLogin的loginKey
* @return 当前StpLogin的loginKey
*/
@ -697,6 +764,7 @@ public class StpUserUtil {
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.login() 使用方式保持不变 </h1>
*
* 在当前会话上登录id
* @param loginId 登录id建议的类型long | int | String
*/
@ -707,6 +775,7 @@ public class StpUserUtil {
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.login() 使用方式保持不变 </h1>
*
* 在当前会话上登录id, 并指定登录设备
* @param loginId 登录id建议的类型long | int | String
* @param device 设备标识
@ -718,6 +787,7 @@ public class StpUserUtil {
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.login() 使用方式保持不变 </h1>
*
* 在当前会话上登录id, 并指定登录设备
* @param loginId 登录id建议的类型long | int | String
* @param isLastingCookie 是否为持久Cookie
@ -729,6 +799,7 @@ public class StpUserUtil {
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.login() 使用方式保持不变 </h1>
*
* 在当前会话上登录id, 并指定所有登录参数Model
* @param loginId 登录id建议的类型long | int | String
* @param loginModel 此次登录的参数Model
@ -738,4 +809,27 @@ public class StpUserUtil {
stpLogic.login(loginId, loginModel);
}
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.kickout() 使用方式保持不变 </h1>
*
* 会话注销根据账号id 踢人下线
* <p> 当对方再次访问系统时会抛出NotLoginException异常场景值=-2
* @param loginId 账号id
*/
public static void logoutByLoginId(Object loginId) {
stpLogic.kickout(loginId);
}
/**
* <h1> 本函数设计已过时未来版本可能移除此函数请及时更换为 StpUtil.kickout() 使用方式保持不变 </h1>
*
* 会话注销根据账号id and 设备标识 踢人下线
* <p> 当对方再次访问系统时会抛出NotLoginException异常场景值=-2 </p>
* @param loginId 账号id
* @param device 设备标识 (填null代表所有注销设备)
*/
public static void logoutByLoginId(Object loginId, String device) {
stpLogic.kickout(loginId, device);
}
}

View File

@ -0,0 +1,12 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.idea/
.factorypath

View File

@ -0,0 +1,71 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-demo-thymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- SpringBoot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/>
</parent>
<!-- 定义sa-token版本号 -->
<properties>
<sa-token-version>1.26.0</sa-token-version>
</properties>
<dependencies>
<!-- springboot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- thymeleaf 视图引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- 在 thymeleaf 标签中使用 Sa-Token -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dialect-thymeleaf</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- 热刷新 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>provided</scope>
</dependency>
<!-- @ConfigurationProperties -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,16 @@
package com.pj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import cn.dev33.satoken.SaManager;
@SpringBootApplication
public class SaTokenThymeleafDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SaTokenThymeleafDemoApplication.class, args);
System.out.println("\n启动成功sa-token配置如下" + SaManager.getConfig());
}
}

View File

@ -0,0 +1,33 @@
package com.pj.satoken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.thymeleaf.dialect.SaTokenDialect;
/**
* [Sa-Token 权限认证] 配置类
* @author kong
*
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// Sa-Token 标签方言 (Thymeleaf版)
@Bean
public SaTokenDialect getSaTokenDialect() {
return new SaTokenDialect();
}
// Thymeleaf 注入全局变量以便在页面中调用 Sa-Token 的方法
@Autowired
private void configureThymeleafStaticVars(ThymeleafViewResolver viewResolver) {
viewResolver.addStaticVariable("stp", StpUtil.stpLogic);
}
}

View File

@ -0,0 +1,44 @@
package com.pj.satoken;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import cn.dev33.satoken.stp.StpInterface;
/**
* 自定义权限验证接口扩展
*/
@Component // 打开此注解保证此类被springboot扫描即可完成sa-token的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一个账号所拥有的权限码集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 本list仅做模拟实际项目中要根据具体业务逻辑来查询权限
List<String> list = new ArrayList<String>();
list.add("101");
list.add("user-add");
list.add("user-delete");
list.add("user-update");
list.add("user-get");
list.add("article-get");
return list;
}
/**
* 返回一个账号所拥有的角色标识集合
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 本list仅做模拟实际项目中要根据具体业务逻辑来查询角色
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;
}
}

View File

@ -0,0 +1,24 @@
package com.pj.test;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import cn.dev33.satoken.util.SaResult;
/**
* 全局异常处理
*/
@RestControllerAdvice
public class GlobalException {
// 全局异常拦截拦截项目中的所有异常
@ExceptionHandler
public SaResult handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) throws Exception {
e.printStackTrace();
return SaResult.error(e.getMessage());
}
}

View File

@ -0,0 +1,40 @@
package com.pj.test;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token-SSO Server端 Controller
* @author kong
*
*/
@RestController
public class TestController {
// 首页
@RequestMapping("/")
public Object index() {
return new ModelAndView("index.html");
}
// 登录
@RequestMapping("login")
public SaResult login(@RequestParam(defaultValue="10001") String id) {
StpUtil.login(id);
StpUtil.getSession().set("name", "zhangsan");
return SaResult.ok();
}
// 注销
@RequestMapping("logout")
public SaResult logout() {
StpUtil.logout();
return SaResult.ok();
}
}

View File

@ -0,0 +1,43 @@
# 端口
server:
port: 8081
# sa-token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: satoken
# token有效期单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: -1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: true
# token风格
token-style: uuid
spring:
# redis配置
redis:
# Redis数据库索引默认为0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10000ms
lettuce:
pool:
# 连接池最大连接数
max-active: 200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 10
# 连接池中的最小空闲连接
min-idle: 0

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<title>Sa-Token 集成 Thymeleaf 标签方言</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
<body>
<div class="view-box" style="padding: 30px;">
<h2>Sa-Token 集成 Thymeleaf 标签方言 —— 测试页面</h2>
<p>
<a href="login" target="_blank">登录</a>
<a href="logout" target="_blank">注销</a>
</p>
<p>登录之后才能显示:<span sa:login>value</span></p>
<p>不登录之后才能显示:<span sa:notLogin>value</span></p>
<p>具有角色 admin 才能显示:<span sa:hasRole="admin">value</span></p>
<p>同时具备多个角色才能显示:<span sa:hasRoleAnd="admin, ceo, cto">value</span></p>
<p>只要具有其中一个角色就能显示:<span sa:hasRoleOr="admin, ceo, cto">value</span></p>
<p>不具有角色 admin 才能显示:<span sa:lackRole="admin">value</span></p>
<p>具有权限 user-add 才能显示:<span sa:hasPermission="user-add">value</span></p>
<p>同时具备多个权限才能显示:<span sa:hasPermissionAnd="user-add, user-delete, user-get">value</span></p>
<p>只要具有其中一个权限就能显示:<span sa:hasPermissionOr="user-add, user-delete, user-get">value</span></p>
<p>不具有权限 user-add 才能显示:<span sa:lackPermission="user-add">value</span></p>
<p th:if="${stp.isLogin()}">
从SaSession中取值
<span th:text="${stp.getSession().get('name', )}"></span>
</p>
</div>
</body>
</html>

View File

@ -2,7 +2,7 @@
在某些敏感操作下,我们需要对已登录的会话进行二次验证
比如 Gitee 的仓库删除操作,虽然我们已经登录了账号,当我们点击 **[删除]** 按钮时,还是需要再次输入一遍密码,这么做主要为了两点:
比如代码托管平台的仓库删除操作,尽管我们已经登录了账号,当我们点击 **[删除]** 按钮时,还是需要再次输入一遍密码,这么做主要为了两点:
1. 保证操作者是当前账号本人
2. 增加操作步骤,防止误删除重要数据

View File

@ -20,6 +20,7 @@
<module>sa-token-alone-redis</module>
<module>sa-token-dao-redis</module>
<module>sa-token-dao-redis-jackson</module>
<module>sa-token-dialect-thymeleaf</module>
<module>sa-token-oauth2</module>
<module>sa-token-quick-login</module>
<module>sa-token-spring-aop</module>

View File

@ -0,0 +1,12 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.factorypath
.idea/

View File

@ -0,0 +1,41 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-plugin</artifactId>
<version>1.26.0</version>
</parent>
<packaging>jar</packaging>
<name>sa-token-dialect-thymeleaf</name>
<artifactId>sa-token-dialect-thymeleaf</artifactId>
<description>sa-token-dialect-thymeleaf</description>
<dependencies>
<!-- sa-token-spring-boot-starter -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.9.RELEASE</version>
<optional>true</optional>
</dependency>
<!-- spring-boot-configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.0.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,82 @@
package cn.dev33.satoken.thymeleaf.dialect;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.thymeleaf.dialect.AbstractProcessorDialect;
import org.thymeleaf.processor.IProcessor;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 集成 Thymeleaf 标签方言
*
* @author kong
*
*/
public class SaTokenDialect extends AbstractProcessorDialect {
/**
* 底层使用的 StpLogic
*/
public StpLogic stpLogic;
/**
* 使用默认参数注册方言
*/
public SaTokenDialect() {
this("sa", 1000, StpUtil.stpLogic);
}
/**
* 构造方言对象使用
* @param name 方言名称
* @param recedence 优先级
* @param stpLogic 使用的 StpLogic 对象
*/
public SaTokenDialect(String name, int recedence, StpLogic stpLogic) {
// 名称前缀优先级
super(name, name, recedence);
this.stpLogic = stpLogic;
}
/**
* 返回所有方言处理器
*/
@Override
public Set<IProcessor> getProcessors(String prefix) {
return new HashSet<IProcessor>(Arrays.asList(
// 登录判断
new SaTokenTagProcessor(prefix, "login", value -> stpLogic.isLogin()),
new SaTokenTagProcessor(prefix, "notLogin", value -> stpLogic.isLogin() == false),
// 角色判断
new SaTokenTagProcessor(prefix, "hasRole", value -> stpLogic.hasRole(value)),
new SaTokenTagProcessor(prefix, "hasRoleOr", value -> stpLogic.hasRoleOr(toArray(value))),
new SaTokenTagProcessor(prefix, "hasRoleAnd", value -> stpLogic.hasRoleAnd(toArray(value))),
new SaTokenTagProcessor(prefix, "lackRole", value -> stpLogic.hasRole(value) == false),
// 权限判断
new SaTokenTagProcessor(prefix, "hasPermission", value -> stpLogic.hasPermission(value)),
new SaTokenTagProcessor(prefix, "hasPermissionOr", value -> stpLogic.hasPermissionOr(toArray(value))),
new SaTokenTagProcessor(prefix, "hasPermissionAnd", value -> stpLogic.hasPermissionAnd(toArray(value))),
new SaTokenTagProcessor(prefix, "lackPermission", value -> stpLogic.hasPermission(value) == false)
));
}
/**
* String Array
* @param str 字符串
* @return 数组
*/
public String[] toArray(String str) {
List<String> list = SaFoxUtil.convertStringToList(str);
return list.toArray(new String[list.size()]);
}
}

View File

@ -0,0 +1,45 @@
package cn.dev33.satoken.thymeleaf.dialect;
import java.util.function.Function;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.templatemode.TemplateMode;
/**
* 封装 Sa-Token 标签方言处理器
* @author kong
*
*/
public class SaTokenTagProcessor extends AbstractAttributeTagProcessor {
Function <String, Boolean> fun;
public SaTokenTagProcessor(final String dialectPrefix, String arrtName, Function <String, Boolean> fun) {
super(
TemplateMode.HTML, // This processor will apply only to HTML mode
dialectPrefix, // Prefix to be applied to name for matching
null, // No tag name: match any tag name
false, // No prefix to be applied to tag name
arrtName, // Name of the attribute that will be matched
true, // Apply dialect prefix to attribute name
10000, // Precedence (inside dialect's own precedence)
true); // Remove the matched attribute afterwards
this.fun = fun;
}
@Override
protected void doProcess(
final ITemplateContext context, final IProcessableElementTag tag,
final AttributeName attributeName, final String attributeValue,
final IElementTagStructureHandler structureHandler) {
// 执行表达式返回值为false则删除这个标签
if(this.fun.apply(attributeValue) == false) {
structureHandler.removeElement();
};
}
}

View File

@ -16,6 +16,8 @@ import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempInterface;
/**
@ -125,6 +127,15 @@ public class SaBeanInject {
public void setSaSsoTemplate(SaSsoTemplate saSsoTemplate) {
SaSsoUtil.saSsoTemplate = saSsoTemplate;
}
/**
* 注入自定义的 StpLogic
* @param stpLogic /
*/
@Autowired(required = false)
public void setStpLogic(StpLogic stpLogic) {
StpUtil.setStpLogic(stpLogic);
}
/**
* 利用自动注入特性获取Spring框架内部使用的路由匹配器
@ -137,5 +148,4 @@ public class SaBeanInject {
SaPathMatcherHolder.setPathMatcher(pathMatcher);
}
}

View File

@ -7,6 +7,7 @@ import org.noear.solon.core.Plugin;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.action.SaTokenAction;
import cn.dev33.satoken.annotation.SaCheckBasic;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
@ -23,6 +24,8 @@ import cn.dev33.satoken.solon.integration.SaTokenMethodInterceptor;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempInterface;
/**
@ -38,6 +41,7 @@ public class XPluginImp implements Plugin {
Aop.context().beanAroundAdd(SaCheckRole.class, SaTokenMethodInterceptor.INSTANCE);
Aop.context().beanAroundAdd(SaCheckLogin.class, SaTokenMethodInterceptor.INSTANCE);
Aop.context().beanAroundAdd(SaCheckSafe.class, SaTokenMethodInterceptor.INSTANCE);
Aop.context().beanAroundAdd(SaCheckBasic.class, SaTokenMethodInterceptor.INSTANCE);
//集成初始化
@ -87,6 +91,11 @@ public class XPluginImp implements Plugin {
Aop.getAsyn(SaSsoTemplate.class, bw->{
SaSsoUtil.saSsoTemplate = bw.raw();
});
// 自定义 StpLogic 对象
Aop.getAsyn(StpLogic.class, bw->{
StpUtil.setStpLogic(bw.raw());
});
}

View File

@ -16,6 +16,8 @@ import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.sso.SaSsoTemplate;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempInterface;
/**
@ -125,6 +127,15 @@ public class SaBeanInject {
public void setSaSsoTemplate(SaSsoTemplate saSsoTemplate) {
SaSsoUtil.saSsoTemplate = saSsoTemplate;
}
/**
* 注入自定义的 StpLogic
* @param stpLogic /
*/
@Autowired(required = false)
public void setStpLogic(StpLogic stpLogic) {
StpUtil.setStpLogic(stpLogic);
}
/**
* 利用自动注入特性获取Spring框架内部使用的路由匹配器