新增 jboot,jfinal项目的运行插件

This commit is contained in:
赵锋 2021-11-23 16:29:52 +08:00
parent 25a649df95
commit 40a6da10fe
20 changed files with 1414 additions and 0 deletions

View File

@ -21,6 +21,8 @@
<module>sa-token-spring-boot-starter</module>
<module>sa-token-reactor-spring-boot-starter</module>
<module>sa-token-solon-plugin</module>
<module>sa-token-jboot-plugin</module>
<module>sa-token-jfinal-plugin</module>
</modules>
</project>

View File

@ -0,0 +1,55 @@
<?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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sa-token-starter</artifactId>
<groupId>cn.dev33</groupId>
<version>1.28.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>sa-token-jboot-plugin</artifactId>
<description>jboot integrate sa-token</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.jboot</groupId>
<artifactId>jboot</artifactId>
<version>3.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${sa-token-version}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-servlet</artifactId>
<version>${sa-token-version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArgument>-parameters</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,60 @@
package cn.dev33.satoken.jboot;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PathAnalyzer {
private static Map<String, PathAnalyzer> cached = new LinkedHashMap();
private Pattern pattern;
public static PathAnalyzer get(String expr) {
PathAnalyzer pa = (PathAnalyzer)cached.get(expr);
if (pa == null) {
synchronized(expr.intern()) {
pa = (PathAnalyzer)cached.get(expr);
if (pa == null) {
pa = new PathAnalyzer(expr);
cached.put(expr, pa);
}
}
}
return pa;
}
private PathAnalyzer(String expr) {
this.pattern = Pattern.compile(exprCompile(expr), 2);
}
public Matcher matcher(String uri) {
return this.pattern.matcher(uri);
}
public boolean matches(String uri) {
return this.pattern.matcher(uri).find();
}
private static String exprCompile(String expr) {
String p = expr.replace(".", "\\.");
p = p.replace("$", "\\$");
p = p.replace("**", ".[]");
p = p.replace("*", "[^/]*");
if (p.indexOf("{") >= 0) {
if (p.indexOf("_}") > 0) {
p = p.replaceAll("\\{[^\\}]+?\\_\\}", "(.+?)");
}
p = p.replaceAll("\\{[^\\}]+?\\}", "([^/]+?)");
}
if (!p.startsWith("/")) {
p = "/" + p;
}
p = p.replace(".[]", ".*");
return "^" + p + "$";
}
}

View File

@ -0,0 +1,16 @@
package cn.dev33.satoken.jboot;
import cn.dev33.satoken.strategy.SaStrategy;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
/**
* 注解式鉴权 - 拦截器
*/
public class SaAnnotationInterceptor implements Interceptor {
@Override
public void intercept(Invocation invocation) {
SaStrategy.me.checkMethodAnnotation.accept((invocation.getMethod()));
invocation.invoke();
}
}

View File

@ -0,0 +1,52 @@
package cn.dev33.satoken.jboot;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
import io.jboot.web.controller.JbootControllerContext;
/**
* Sa-Token 上下文处理器 [Jboot 版本实现]
*/
public class SaTokenContextForJboot implements SaTokenContext {
/**
* 获取当前请求的Request对象
*/
@Override
public SaRequest getRequest() {
return new SaRequestForServlet(JbootControllerContext.get().getRequest());
}
/**
* 获取当前请求的Response对象
*/
@Override
public SaResponse getResponse() {
return new SaResponseForServlet(JbootControllerContext.get().getResponse());
}
/**
* 获取当前请求的 [存储器] 对象
*/
@Override
public SaStorage getStorage() {
return new SaStorageForServlet(JbootControllerContext.get().getRequest());
}
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*/
@Override
public boolean matchPath(String pattern, String path) {
return PathAnalyzer.get(pattern).matches(path);
}
@Override
public boolean isValid() {
return SaTokenContext.super.isValid();
}
}

View File

@ -0,0 +1,219 @@
package cn.dev33.satoken.jboot;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaFoxUtil;
import io.jboot.Jboot;
import io.jboot.components.cache.redis.JbootRedisCacheConfig;
import io.jboot.exception.JbootIllegalConfigException;
import io.jboot.support.redis.JbootRedis;
import io.jboot.support.redis.JbootRedisManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class SaTokenDaoRedis implements SaTokenDao {
private final JbootRedis redis;
/**
* 标记是否已初始化成功
*/
public boolean isInit;
public SaTokenDaoRedis(){
JbootRedisCacheConfig redisConfig = Jboot.config(JbootRedisCacheConfig.class);
//优先使用 jboot.cache.redis 的配置
if (redisConfig.isConfigOk()) {
redis = JbootRedisManager.me().getRedis(redisConfig);
}
// jboot.cache.redis 配置不存在时
// 使用 jboot.redis 的配置
else {
redis = Jboot.getRedis();
}
if (redis == null) {
this.isInit = false;
throw new JbootIllegalConfigException("can not get redis, please check your jboot.properties , please correct config jboot.cache.redis.host or jboot.redis.host ");
}else{
this.isInit = true;
}
}
/**
* 获取Value如无返空
* @param key
* @return
*/
@Override
public String get(String key) {
return redis.get(key);
}
/**
* 写入Value并设定存活时间 (单位: )
* @param key
* @param value
* @param timeout
*/
@Override
public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
if(timeout == SaTokenDao.NEVER_EXPIRE) {
redis.set(key, value);
}else{
redis.setex(key,Integer.parseInt(timeout+""),value);
}
}
/**
* 修改指定key-value键值对 (过期时间不变)
* @param key
* @param value
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.set(key,value,expire);
}
/**
* 删除Value
* @param key
*/
@Override
public void delete(String key) {
redis.del(key);
}
/**
* 获取Value的剩余存活时间 (单位: )
* @param key
* @return
*/
@Override
public long getTimeout(String key) {
return redis.ttl(key);
}
/**
* 修改Value的剩余存活时间 (单位: )
* @param key
* @param timeout
*/
@Override
public void updateTimeout(String key, long timeout) {
//判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
redis.expire(key,Integer.parseInt(timeout+""));
}
/**
* 获取Object如无返空
* @param key
* @return
*/
@Override
public Object getObject(String key) {
return redis.get(key);
}
/**
* 写入Object并设定存活时间 (单位: )
* @param key
* @param object
* @param timeout
*/
@Override
public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
if(timeout == SaTokenDao.NEVER_EXPIRE) {
redis.set(key, object);
}else{
redis.setex(key,Integer.parseInt(timeout+""),object);
}
}
/**
* 更新Object (过期时间不变)
* @param key
* @param object
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.setObject(key, object, expire);
}
/**
* 删除Object
* @param key
*/
@Override
public void deleteObject(String key) {
redis.del(key);
}
@Override
public long getObjectTimeout(String key) {
return redis.ttl(key);
}
/**
* 修改Object的剩余存活时间 (单位: )
* @param key
* @param timeout
*/
@Override
public void updateObjectTimeout(String key, long timeout) {
//判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
redis.expire(key,Integer.parseInt(timeout+""));
}
/**
* 搜索数据
* @param prefix
* @param keyword
* @param start
* @param size
* @return
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size) {
Set<String> keys = redis.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<String>(keys);
return SaFoxUtil.searchList(list, start, size);
}
}

View File

@ -0,0 +1,35 @@
package cn.dev33.satoken.jboot.test;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import io.jboot.app.JbootApplication;
import io.jboot.web.controller.JbootController;
import io.jboot.web.controller.annotation.RequestMapping;
@RequestMapping("/")
public class AppRun extends JbootController {
public static void main(String[] args) {
JbootApplication.run(args);
}
public void index(){
renderText("index");
}
public void doLogin(){
StpUtil.login(10001);
//赋值角色
renderText("登录成功");
}
public void getLoginInfo(){
System.out.println("是否登录:"+StpUtil.isLogin());
System.out.println("登录信息"+StpUtil.getTokenInfo());
renderJson(StpUtil.getTokenInfo());
}
@SaCheckRole("super-admin")
public void add(){
renderText("超级管理员方法!");
}
}

View File

@ -0,0 +1,77 @@
package cn.dev33.satoken.jboot.test;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaTokenContext;
import com.jfinal.config.Constants;
import com.jfinal.config.Interceptors;
import com.jfinal.config.Routes;
import com.jfinal.template.Engine;
import cn.dev33.satoken.jboot.SaAnnotationInterceptor;
import cn.dev33.satoken.jboot.SaTokenContextForJboot;
import cn.dev33.satoken.jboot.SaTokenDaoRedis;
import io.jboot.aop.jfinal.JfinalHandlers;
import io.jboot.aop.jfinal.JfinalPlugins;
import io.jboot.core.listener.JbootAppListener;
public class AtteStartListener implements JbootAppListener {
public void onInit() {
//注册权限验证功能由saToken处理请求上下文
SaTokenContext saTokenContext = new SaTokenContextForJboot();
SaManager.setSaTokenContext(saTokenContext);
//加载权限角色设置数据接口
SaManager.setStpInterface(new StpInterfaceImpl());
//增加redis缓存,需要先配置redis地址
// SaManager.setSaTokenDao(new SaTokenDaoRedis());
}
@Override
public void onConstantConfig(Constants constants) {
}
@Override
public void onRouteConfig(Routes routes) {
}
@Override
public void onEngineConfig(Engine engine) {
}
@Override
public void onPluginConfig(JfinalPlugins plugins) {
}
@Override
public void onInterceptorConfig(Interceptors interceptors) {
//开启注解方式权限验证
interceptors.add(new SaAnnotationInterceptor());
}
@Override
public void onHandlerConfig(JfinalHandlers handlers) {
}
@Override
public void onStartBefore() {
}
@Override
public void onStart() {
}
@Override
public void onStartFinish() {
}
@Override
public void onStop() {
}
}

View File

@ -0,0 +1,23 @@
package cn.dev33.satoken.jboot.test;
import cn.dev33.satoken.stp.StpInterface;
import io.jboot.aop.annotation.Bean;
import java.util.ArrayList;
import java.util.List;
@Bean
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object o, String s) {
return null;
}
@Override
public List<String> getRoleList(Object o, String s) {
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;
}
}

View File

@ -0,0 +1,88 @@
<?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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sa-token-starter</artifactId>
<groupId>cn.dev33</groupId>
<version>1.28.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>sa-token-jfinal-plugin</artifactId>
<description>jfinal integrate sa-token</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal-undertow</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>4.9.17</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${sa-token-version}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-servlet</artifactId>
<version>${sa-token-version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>2.29</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArgument>-parameters</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,60 @@
package cn.dev33.satoken.jfinal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PathAnalyzer {
private static Map<String, PathAnalyzer> cached = new LinkedHashMap();
private Pattern pattern;
public static PathAnalyzer get(String expr) {
PathAnalyzer pa = (PathAnalyzer)cached.get(expr);
if (pa == null) {
synchronized(expr.intern()) {
pa = (PathAnalyzer)cached.get(expr);
if (pa == null) {
pa = new PathAnalyzer(expr);
cached.put(expr, pa);
}
}
}
return pa;
}
private PathAnalyzer(String expr) {
this.pattern = Pattern.compile(exprCompile(expr), 2);
}
public Matcher matcher(String uri) {
return this.pattern.matcher(uri);
}
public boolean matches(String uri) {
return this.pattern.matcher(uri).find();
}
private static String exprCompile(String expr) {
String p = expr.replace(".", "\\.");
p = p.replace("$", "\\$");
p = p.replace("**", ".[]");
p = p.replace("*", "[^/]*");
if (p.indexOf("{") >= 0) {
if (p.indexOf("_}") > 0) {
p = p.replaceAll("\\{[^\\}]+?\\_\\}", "(.+?)");
}
p = p.replaceAll("\\{[^\\}]+?\\}", "([^/]+?)");
}
if (!p.startsWith("/")) {
p = "/" + p;
}
p = p.replace(".[]", ".*");
return "^" + p + "$";
}
}

View File

@ -0,0 +1,16 @@
package cn.dev33.satoken.jfinal;
import cn.dev33.satoken.strategy.SaStrategy;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
/**
* 注解式鉴权 - 拦截器
*/
public class SaAnnotationInterceptor implements Interceptor {
@Override
public void intercept(Invocation invocation) {
SaStrategy.me.checkMethodAnnotation.accept((invocation.getMethod()));
invocation.invoke();
}
}

View File

@ -0,0 +1,20 @@
package cn.dev33.satoken.jfinal;
import com.jfinal.core.Controller;
public class SaControllerContext {
private static ThreadLocal<Controller> controllers = new ThreadLocal<>();
public static void hold(Controller controller) {
controllers.set(controller);
}
public static Controller get() {
return controllers.get();
}
public static void release() {
controllers.remove();
}
}

View File

@ -0,0 +1,155 @@
package cn.dev33.satoken.jfinal;
import com.jfinal.aop.Invocation;
import com.jfinal.config.Constants;
import com.jfinal.core.*;
import com.jfinal.kit.ReflectKit;
import com.jfinal.log.Log;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;
import com.jfinal.render.RenderManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SaTokenActionHandler extends ActionHandler {
protected boolean devMode;
protected ActionMapping actionMapping;
protected ControllerFactory controllerFactory;
protected ActionReporter actionReporter;
protected static final RenderManager renderManager = RenderManager.me();
private static final Log log = Log.getLog(ActionHandler.class);
protected void init(ActionMapping actionMapping, Constants constants) {
this.actionMapping = actionMapping;
this.devMode = constants.getDevMode();
this.controllerFactory = constants.getControllerFactory();
this.actionReporter = constants.getActionReporter();
}
/**
* 子类覆盖 getAction 方法可以定制路由功能
*/
protected Action getAction(String target, String[] urlPara) {
return actionMapping.getAction(target, urlPara);
}
@Override
public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
if (target.indexOf('.') != -1) {
return ;
}
isHandled[0] = true;
String[] urlPara = {null};
Action action = getAction(target, urlPara);
if (action == null) {
if (log.isWarnEnabled()) {
String qs = request.getQueryString();
log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs));
}
renderManager.getRenderFactory().getErrorRender(404).setContext(request, response).render();
return ;
}
Controller controller = null;
try {
// Controller controller = action.getControllerClass().newInstance();
controller = controllerFactory.getController(action.getControllerClass());
CPI._init_(controller, action, request, response, urlPara[0]);
//加入SaToken上下文处理
SaControllerContext.hold(controller);
if (devMode) {
if (actionReporter.isReportAfterInvocation(request)) {
new Invocation(action, controller).invoke();
actionReporter.report(target, controller, action);
} else {
actionReporter.report(target, controller, action);
new Invocation(action, controller).invoke();
}
}
else {
new Invocation(action, controller).invoke();
}
Render render = controller.getRender();
if (render instanceof ForwardActionRender) {
String actionUrl = ((ForwardActionRender)render).getActionUrl();
if (target.equals(actionUrl)) {
throw new RuntimeException("The forward action url is the same as before.");
} else {
handle(actionUrl, request, response, isHandled);
}
return ;
}
if (render == null) {
render = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName());
}
render.setContext(request, response, action.getViewPath()).render();
}
catch (RenderException e) {
if (log.isErrorEnabled()) {
String qs = request.getQueryString();
log.error(qs == null ? target : target + "?" + qs, e);
}
}
catch (ActionException e) {
handleActionException(target, request, response, action, e);
}
catch (Exception e) {
if (log.isErrorEnabled()) {
String qs = request.getQueryString();
String targetInfo = (qs == null ? target : target + "?" + qs);
String sign = ReflectKit.getMethodSignature(action.getMethod());
log.error(sign + " : " + targetInfo, e);
}
renderManager.getRenderFactory().getErrorRender(500).setContext(request, response, action.getViewPath()).render();
} finally {
SaControllerContext.release();
controllerFactory.recycle(controller);
}
}
/**
* 抽取出该方法是为了缩短 handle 方法中的代码量确保获得 JIT 优化
* 方法长度超过 8000 个字节码时将不会被 JIT 编译成二进制码
*
* 通过开启 java -XX:+PrintCompilation 启动参数得知handle(...)
* 方法(73 行代码)已被 JIT 优化优化后的字节码长度为 593 个字节相当于
* 每行代码产生 8.123 个字节
*/
private void handleActionException(String target, HttpServletRequest request, HttpServletResponse response, Action action, ActionException e) {
int errorCode = e.getErrorCode();
String msg = null;
if (errorCode == 404) {
msg = "404 Not Found: ";
} else if (errorCode == 400) {
msg = "400 Bad Request: ";
} else if (errorCode == 401) {
msg = "401 Unauthorized: ";
} else if (errorCode == 403) {
msg = "403 Forbidden: ";
}
if (msg != null) {
if (log.isWarnEnabled()) {
String qs = request.getQueryString();
msg = msg + (qs == null ? target : target + "?" + qs);
if (e.getMessage() != null) {
msg = msg + "\n" + e.getMessage();
}
log.warn(msg);
}
} else {
if (log.isErrorEnabled()) {
String qs = request.getQueryString();
log.error(errorCode + " Error: " + (qs == null ? target : target + "?" + qs), e);
}
}
e.getErrorRender().setContext(request, response, action.getViewPath()).render();
}
}

View File

@ -0,0 +1,51 @@
package cn.dev33.satoken.jfinal;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
/**
* Sa-Token 上线文处理器 [Jfinal 版本实现]
*/
public class SaTokenContextForJfinal implements SaTokenContext {
/**
* 获取当前请求的Request对象
*/
@Override
public SaRequest getRequest() {
return new SaRequestForServlet(SaControllerContext.get().getRequest());
}
/**
* 获取当前请求的Response对象
*/
@Override
public SaResponse getResponse() {
return new SaResponseForServlet(SaControllerContext.get().getResponse());
}
/**
* 获取当前请求的 [存储器] 对象
*/
@Override
public SaStorage getStorage() {
return new SaStorageForServlet(SaControllerContext.get().getRequest());
}
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*/
@Override
public boolean matchPath(String pattern, String path) {
return PathAnalyzer.get(pattern).matches(path);
}
@Override
public boolean isValid() {
return SaTokenContext.super.isValid();
}
}

View File

@ -0,0 +1,200 @@
package cn.dev33.satoken.jfinal;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaFoxUtil;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class SaTokenDaoRedis implements SaTokenDao {
private Cache redis = null;
/**
* 标记是否已初始化成功
*/
public boolean isInit;
public SaTokenDaoRedis(String confName){
redis = Redis.use(confName);
this.isInit = redis != null;
}
/**
* 获取Value如无返空
* @param key
* @return
*/
@Override
public String get(String key) {
return redis.get(key);
}
/**
* 写入Value并设定存活时间 (单位: )
* @param key
* @param value
* @param timeout
*/
@Override
public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
if(timeout == SaTokenDao.NEVER_EXPIRE) {
redis.set(key, value);
}else{
redis.setex(key,Integer.parseInt(timeout+""),value);
}
}
/**
* 修改指定key-value键值对 (过期时间不变)
* @param key
* @param value
*/
@Override
public void update(String key, String value) {
long expire = getTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.set(key,value,expire);
}
/**
* 删除Value
* @param key
*/
@Override
public void delete(String key) {
redis.del(key);
}
/**
* 获取Value的剩余存活时间 (单位: )
* @param key
* @return
*/
@Override
public long getTimeout(String key) {
return redis.ttl(key);
}
/**
* 修改Value的剩余存活时间 (单位: )
* @param key
* @param timeout
*/
@Override
public void updateTimeout(String key, long timeout) {
//判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
redis.expire(key,Integer.parseInt(timeout+""));
}
/**
* 获取Object如无返空
* @param key
* @return
*/
@Override
public Object getObject(String key) {
return redis.get(key);
}
/**
* 写入Object并设定存活时间 (单位: )
* @param key
* @param object
* @param timeout
*/
@Override
public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
if(timeout == SaTokenDao.NEVER_EXPIRE) {
redis.set(key, object);
}else{
redis.setex(key,Integer.parseInt(timeout+""),object);
}
}
/**
* 更新Object (过期时间不变)
* @param key
* @param object
*/
@Override
public void updateObject(String key, Object object) {
long expire = getObjectTimeout(key);
// -2 = 无此键
if(expire == SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
this.setObject(key, object, expire);
}
/**
* 删除Object
* @param key
*/
@Override
public void deleteObject(String key) {
redis.del(key);
}
@Override
public long getObjectTimeout(String key) {
return redis.ttl(key);
}
/**
* 修改Object的剩余存活时间 (单位: )
* @param key
* @param timeout
*/
@Override
public void updateObjectTimeout(String key, long timeout) {
//判断是否想要设置为永久
if(timeout == SaTokenDao.NEVER_EXPIRE) {
long expire = getTimeout(key);
if(expire == SaTokenDao.NEVER_EXPIRE) {
// 如果其已经被设置为永久则不作任何处理
} else {
// 如果尚未被设置为永久那么再次set一次
this.set(key, this.get(key), timeout);
}
return;
}
redis.expire(key,Integer.parseInt(timeout+""));
}
/**
* 搜索数据
* @param prefix
* @param keyword
* @param start
* @param size
* @return
*/
@Override
public List<String> searchData(String prefix, String keyword, int start, int size) {
Set<String> keys = redis.keys(prefix + "*" + keyword + "*");
List<String> list = new ArrayList<String>(keys);
return SaFoxUtil.searchList(list, start, size);
}
}

View File

@ -0,0 +1,154 @@
package cn.dev33.satoken.jfinal;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SaTokenPathFilter {
// ------------------------ 设置此过滤器 拦截 & 放行 的路由
/**
* 拦截路由
*/
private List<String> includeList = new ArrayList<>();
/**
* 放行路由
*/
private List<String> excludeList = new ArrayList<>();
/**
* 添加 [拦截路由]
* @param paths 路由
* @return 对象自身
*/
public SaTokenPathFilter addInclude(String... paths) {
includeList.addAll(Arrays.asList(paths));
return this;
}
/**
* 添加 [放行路由]
* @param paths 路由
* @return 对象自身
*/
public SaTokenPathFilter addExclude(String... paths) {
excludeList.addAll(Arrays.asList(paths));
return this;
}
/**
* 写入 [拦截路由] 集合
* @param pathList 路由集合
* @return 对象自身
*/
public SaTokenPathFilter setIncludeList(List<String> pathList) {
includeList = pathList;
return this;
}
/**
* 写入 [放行路由] 集合
* @param pathList 路由集合
* @return 对象自身
*/
public SaTokenPathFilter setExcludeList(List<String> pathList) {
excludeList = pathList;
return this;
}
/**
* 获取 [拦截路由] 集合
* @return see note
*/
public List<String> getIncludeList() {
return includeList;
}
/**
* 获取 [放行路由] 集合
* @return see note
*/
public List<String> getExcludeList() {
return excludeList;
}
// ------------------------ 钩子函数
/**
* 认证函数每次请求执行
*/
public SaFilterAuthStrategy auth = r -> {};
/**
* 异常处理函数每次[认证函数]发生异常时执行此函数
*/
public SaFilterErrorStrategy error = e -> {
throw new SaTokenException(e);
};
/**
* 前置函数在每次[认证函数]之前执行
*/
public SaFilterAuthStrategy beforeAuth = r -> {};
/**
* 写入[认证函数]: 每次请求执行
* @param auth see note
* @return 对象自身
*/
public SaTokenPathFilter setAuth(SaFilterAuthStrategy auth) {
this.auth = auth;
return this;
}
/**
* 写入[异常处理函数]每次[认证函数]发生异常时执行此函数
* @param error see note
* @return 对象自身
*/
public SaTokenPathFilter setError(SaFilterErrorStrategy error) {
this.error = error;
return this;
}
/**
* 写入[前置函数]在每次[认证函数]之前执行
* @param beforeAuth see note
* @return 对象自身
*/
public SaTokenPathFilter setBeforeAuth(SaFilterAuthStrategy beforeAuth) {
this.beforeAuth = beforeAuth;
return this;
}
/*@Override
public void doFilter(Controller ctx, FilterChain chain) throws Throwable {
try {
// 执行全局过滤器
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
beforeAuth.run(null);
auth.run(null);
});
} catch (StopMatchException e) {
} catch (Throwable e) {
// 1. 获取异常处理策略结果
String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
// 2. 写入输出流
ctx.renderText(result);
return;
}
// 执行
chain.doFilter(ctx);
}*/
}

View File

@ -0,0 +1,38 @@
package cn.dev33.satoken.jfinal.test;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import com.jfinal.core.Controller;
import com.jfinal.core.Path;
import com.jfinal.server.undertow.UndertowServer;
@Path("/")
public class AppRun extends Controller {
public static void main(String[] args) {
UndertowServer.create(Config.class)
.addHotSwapClassPrefix("cn.dev33.satoken.jfinal.")
.start();
}
public void index(){
renderText("index");
}
public void doLogin(){
StpUtil.logout();
StpUtil.login(10002);
//赋值角色
renderText("登录成功");
}
public void getLoginInfo(){
System.out.println("是否登录:"+StpUtil.isLogin());
System.out.println("登录信息"+StpUtil.getTokenInfo());
renderJson(StpUtil.getTokenInfo());
}
@SaCheckRole("super-admin")
public void add(){
renderText("超级管理员方法!");
}
}

View File

@ -0,0 +1,72 @@
package cn.dev33.satoken.jfinal.test;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaTokenContext;
import com.jfinal.config.*;
import com.jfinal.plugin.redis.RedisPlugin;
import com.jfinal.template.Engine;
import cn.dev33.satoken.jfinal.SaAnnotationInterceptor;
import cn.dev33.satoken.jfinal.SaTokenActionHandler;
import cn.dev33.satoken.jfinal.SaTokenContextForJfinal;
import cn.dev33.satoken.jfinal.SaTokenDaoRedis;
public class Config extends JFinalConfig {
public Config(){
//注册权限验证功能由saToken处理请求上下文
SaTokenContext saTokenContext = new SaTokenContextForJfinal();
SaManager.setSaTokenContext(saTokenContext);
//加载权限角色设置数据接口
SaManager.setStpInterface(new StpInterfaceImpl());
}
@Override
public void configConstant(Constants constants) {
}
@Override
public void configRoute(Routes routes) {
//路由扫描
routes.scan("cn.dev33.satoken.jfinal");
}
@Override
public void configEngine(Engine engine) {
}
@Override
public void configPlugin(Plugins plugins) {
//添加redis扩展
// plugins.add(createRedisPlugin("satoken",10));
}
@Override
public void configInterceptor(Interceptors interceptors) {
//开启注解方式权限验证
interceptors.add(new SaAnnotationInterceptor());
}
@Override
public void configHandler(Handlers handlers) {
//将上下文交给satoken处理
handlers.setActionHandler(new SaTokenActionHandler());
}
/**
* 创建Redis插件
* @param name 名称
* @param dbIndex 使用的库ID
* @return
*/
private RedisPlugin createRedisPlugin(String name, Integer dbIndex) {
return new RedisPlugin(name, "redis-host", 6379, 3000,"pwd",dbIndex);
}
@Override
public void onStart(){
//增加redis缓存,需要先配置redis地址
// SaManager.setSaTokenDao(new SaTokenDaoRedis("satoken"));
}
}

View File

@ -0,0 +1,21 @@
package cn.dev33.satoken.jfinal.test;
import cn.dev33.satoken.stp.StpInterface;
import java.util.ArrayList;
import java.util.List;
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object o, String s) {
return null;
}
@Override
public List<String> getRoleList(Object o, String s) {
List<String> list = new ArrayList<String>();
list.add("admin");
list.add("super-admin");
return list;
}
}