v.1.12.0新特性:路由拦截式鉴权

This commit is contained in:
shengzhang 2021-01-11 20:08:17 +08:00
parent ac4ac37175
commit c3bedaef99
8 changed files with 383 additions and 41 deletions

View File

@ -5,7 +5,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.interceptor.SaCheckInterceptor;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
/**
* sa-token代码方式进行配置
@ -30,7 +30,8 @@ public class MySaTokenConfig implements WebMvcConfigurer {
// 注册sa-token的拦截器打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaCheckInterceptor()).addPathPatterns("/**"); // 全局拦截器
// 注册注解拦截器
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); // 全局拦截器
}

View File

@ -234,8 +234,14 @@ public class TestController {
// 测试 浏览器访问 http://localhost:8081/test/test
@RequestMapping("test")
public AjaxJson test() {
StpUtil.getTokenSession().logout();
StpUtil.logoutByLoginId(10001);
// StpUtil.getTokenSession().logout();
// StpUtil.logoutByLoginId(10001);
return AjaxJson.getSuccess();
}
// 测试 浏览器访问 http://localhost:8081/test/test2
@RequestMapping("test2")
public AjaxJson test2() {
return AjaxJson.getSuccess();
}

View File

@ -16,6 +16,7 @@
- [多账号验证](/use/many-account)
- [同端互斥登录](/use/mutex-login)
- [注解式鉴权](/use/at-check)
- [路由拦截式鉴权](/use/route-check)
- [花式token](/use/token-style)
- [框架配置](/use/config)
- [会话治理](/use/search-session)

View File

@ -13,10 +13,10 @@
``` java
@Configuration
public class MySaTokenConfig implements WebMvcConfigurer {
// 注册sa-token的拦截器打开注解式鉴权功能
// 注册sa-token的注解拦截器,打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaCheckInterceptor()).addPathPatterns("/**"); // 全局拦截器
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
}
}
```
@ -119,22 +119,3 @@ public class UserService {
<!-- ## 3、扩展
- 其实在注册拦截器时,我们也可以根据路由前缀设置不同 `StpLogic`, 从而达到不同模块不同鉴权方式的目的
- 以下为参考示例:
``` java
@Configuration
public class MySaTokenConfig implements WebMvcConfigurer {
// 注册sa-token的拦截器打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaCheckInterceptor(StpUtil.stpLogic)).addPathPatterns("/admin/**");
registry.addInterceptor(new SaCheckInterceptor(StpUserUtil.stpLogic)).addPathPatterns("/user/**");
}
}
``` -->

View File

@ -0,0 +1,80 @@
# 路由拦截式鉴权
---
假设我们有如下需求:
> 项目中所有接口均需要登录验证,只有'登录接口'本身对外开放
我们怎么实现呢?给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。<br/>
在这个需求中我们真正需要的是一种基于路由拦截的鉴权模式, 那么在sa-token怎么实现路由拦截鉴权呢
## 1、注册路由拦截器
以`springboot2.0`为例, 新建配置类`MySaTokenConfig.java`
``` java
@Configuration
public class MySaTokenConfig implements WebMvcConfigurer {
// 注册sa-token的登录拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册登录拦截器,并排除登录接口地址
registry.addInterceptor(new SaRouteInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/doLogin");
}
}
```
以上代码,我们注册了一个登录验证拦截器,并且排除了`/user/doLogin`接口用来开放登录 <br>
那么我们如何进行权限认证拦截呢,且往下看
## 2、所有拦截器示例
``` java
@Configuration
public class MySaTokenConfig implements WebMvcConfigurer {
// 注册sa-token的所有拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册一个登录验证拦截器
registry.addInterceptor(SaRouteInterceptor.createLoginVal()).addPathPatterns("/**").excludePathPatterns("/user/doLogin");
// 注册一个角色认证拦截器
registry.addInterceptor(SaRouteInterceptor.createRoleVal("super-admin")).addPathPatterns("/**");
// 注册一个权限认证拦截器
registry.addInterceptor(SaRouteInterceptor.createPermissionVal("user:add", "user:deelete")).addPathPatterns("/UserController/**");
// 注册一个自定义认证拦截器 (可以写任意认证代码)
registry.addInterceptor(new SaRouteInterceptor(new SaFunction() {
@Override
public void run() {
// 你可以写任意认证代码, 例如: StpUtil.checkLogin();
System.out.println("---------- 进入自定义认证 --------------- ");
}
})).addPathPatterns("/**");
/** ------ 如果你使用的JDK版本是1.8或以上,上面那一坨可以简写为以下形式 ------ */
// 注册一个自定义认证拦截器 (可以写任意认证代码)
registry.addInterceptor(new SaRouteInterceptor(()->{
// 你可以写任意认证代码, 例如: StpUtil.checkLogin();
System.out.println("---------- 进入自定义认证2 --------------- ");
})).addPathPatterns("/**");
}
}
```
(你不必像上面的示例一样注册所有拦截器,只要按需注册即可
## 3、所有拦截器示例

View File

@ -15,7 +15,7 @@ import cn.dev33.satoken.stp.StpUtil;
* 注解式鉴权 - 拦截器
* @author kong
*/
public class SaCheckInterceptor implements HandlerInterceptor {
public class SaAnnotationInterceptor implements HandlerInterceptor {
/**
@ -24,23 +24,32 @@ public class SaCheckInterceptor implements HandlerInterceptor {
public StpLogic stpLogic = null;
/**
* 创建并指定一个默认的 StpLogic
* @return 底层的 StpLogic 对象
*/
public SaCheckInterceptor() {
this(StpUtil.stpLogic);
public StpLogic getStpLogic() {
if(stpLogic == null) {
stpLogic = StpUtil.stpLogic;
}
return stpLogic;
}
/**
* 创建并指定一个的 StpLogic
* @param stpLogic 指定的StpLogic
*/
public SaCheckInterceptor(StpLogic stpLogic) {
this.stpLogic = stpLogic;
}
/**
* 每次请求之前触发
* @param stpLogic 底层的 StpLogic 对象
*/
public SaAnnotationInterceptor setStpLogic(StpLogic stpLogic) {
this.stpLogic = stpLogic;
return this;
}
/**
* 创建并指定一个默认的 StpLogic
*/
public SaAnnotationInterceptor() {
}
/**
* 每次请求之前触发的方法
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
@ -53,7 +62,7 @@ public class SaCheckInterceptor implements HandlerInterceptor {
Method method = ((HandlerMethod) handler).getMethod();
// 进行验证
stpLogic.checkMethodAnnotation(method);
getStpLogic().checkMethodAnnotation(method);
// 通过验证
return true;
@ -61,5 +70,4 @@ public class SaCheckInterceptor implements HandlerInterceptor {
}

View File

@ -0,0 +1,15 @@
package cn.dev33.satoken.interceptor;
/**
* 执行验证方法的辅助类
* @author kong
*
*/
public interface SaFunction {
/**
* 执行验证的方法
*/
public void run();
}

View File

@ -0,0 +1,250 @@
package cn.dev33.satoken.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
/**
* sa-token基于路由的拦截式鉴权
* @author kong
*/
public class SaRouteInterceptor implements HandlerInterceptor {
// ----------------- 属性 -----------------
/**
* 底层的 StpLogic 对象
*/
private StpLogic stpLogic;
/**
* 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
*/
private int type;
/**
* 验证模式 AND | OR
*/
private SaMode mode;
/**
* 标识码数组
*/
private String[] codes;
/**
* 自定义模式下的执行函数
*/
private SaFunction function;
/**
* 表示登录验证
*/
public static final int LOGIN = 1;
/**
* 表示角色验证
*/
public static final int ROLE = 2;
/**
* 表示权限验证
*/
public static final int PERMISSION = 3;
/**
* 表示自定义验证
*/
public static final int CUSTOM = 4;
/**
* @return 底层的 StpLogic 对象
*/
public StpLogic getStpLogic() {
if(stpLogic == null) {
stpLogic = StpUtil.stpLogic;
}
return stpLogic;
}
/**
* @param stpLogic 底层的 StpLogic 对象
*/
public SaRouteInterceptor setStpLogic(StpLogic stpLogic) {
this.stpLogic = stpLogic;
return this;
}
/**
* @return 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
*/
public int getType() {
return type;
}
/**
* @param type 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
*/
public SaRouteInterceptor setType(int type) {
this.type = type;
return this;
}
/**
* @return 验证模式 AND | OR
*/
public SaMode getMode() {
return mode;
}
/**
* @param mode 验证模式 AND | OR
*/
public SaRouteInterceptor setMode(SaMode mode) {
this.mode = mode;
return this;
}
/**
* @return 标识码数组
*/
public String[] getCodes() {
return codes;
}
/**
* @param codes 标识码数组
*/
public SaRouteInterceptor setCodes(String... codes) {
this.codes = codes;
return this;
}
/**
* @return 自定义模式下的执行函数
*/
public SaFunction getFunction() {
return function;
}
/**
* @param function 设置自定义模式下的执行函数
*/
public SaRouteInterceptor setFunction(SaFunction function) {
this.type = SaRouteInterceptor.CUSTOM;
this.function = function;
return this;
}
// ----------------- 构建相关 -----------------
/**
* 创建 (全参数)
* @param type 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
* @param mode 验证模式 AND | OR
* @param codes 标识码数组
*/
public SaRouteInterceptor(int type, SaMode mode, String... codes) {
super();
this.type = type;
this.mode = mode;
this.codes = codes;
}
/**
* 创建 (默认为登录验证)
*/
public SaRouteInterceptor() {
this(SaRouteInterceptor.LOGIN, null, new String[0]);
}
/**
* 创建 (默认为自定义认证)
* @param function 自定义模式下的执行函数
*/
public SaRouteInterceptor(SaFunction function) {
this(SaRouteInterceptor.CUSTOM, null, new String[0]);
setFunction(function);
}
/**
* 构建一个模式为登录认证的sa路由拦截器
* @return sa拦截器
*/
public static SaRouteInterceptor createLoginVal() {
return new SaRouteInterceptor();
}
/**
* 构建一个模式为角色认证的sa路由拦截器
* @param roles 需要验证的数组标识列表
* @return sa拦截器
*/
public static SaRouteInterceptor createRoleVal(String... roles) {
return new SaRouteInterceptor(SaRouteInterceptor.ROLE, SaMode.AND, roles);
}
/**
* 构建一个模式为权限认证的sa路由拦截器
* @param permissions 需要验证的数组权限列表
* @return sa拦截器
*/
public static SaRouteInterceptor createPermissionVal(String... permissions) {
return new SaRouteInterceptor(SaRouteInterceptor.PERMISSION, SaMode.AND, permissions);
}
/**
* 创建一个模式为自定义认证的sa路由拦截器
* @param function 自定义模式下的执行函数
* @return sa拦截器
*/
public static SaRouteInterceptor createCustomVal(SaFunction function) {
return new SaRouteInterceptor(function);
}
// ----------------- 验证方法 -----------------
/**
* 每次请求之前触发的方法
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 根据模式进行验证
if(this.type == SaRouteInterceptor.LOGIN) {
getStpLogic().checkLogin();
} else if(this.type == SaRouteInterceptor.ROLE) {
if(mode == SaMode.AND) {
getStpLogic().checkRoleAnd(codes);
} else {
getStpLogic().checkRoleOr(codes);
}
} else if(this.type == SaRouteInterceptor.PERMISSION) {
if(mode == SaMode.AND) {
getStpLogic().checkPermissionAnd(codes);
} else {
getStpLogic().checkPermissionOr(codes);
}
} else if(this.type == SaRouteInterceptor.CUSTOM) {
function.run();
}
// 通过验证
return true;
}
}