diff --git a/README.md b/README.md index b10d1a1d..c68b5965 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ - 持久层扩展(集成redis) - 多账号认证体系(比如一个商城项目的user表和admin表) - 无cookie模式(APP、小程序等前后台分离场景) +- 注解式鉴权(优雅的将鉴权与业务代码分离) - 零配置与Spring等框架集成 - ... diff --git a/sa-token-demo-springboot/pom.xml b/sa-token-demo-springboot/pom.xml index 575bf84d..8a36dcc1 100644 --- a/sa-token-demo-springboot/pom.xml +++ b/sa-token-demo-springboot/pom.xml @@ -25,11 +25,11 @@ spring-boot-starter-aop - + cn.dev33 sa-token - 1.0.1 + 1.0.2 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 846eff03..cc2c8265 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 @@ -1,18 +1,18 @@ -//package com.pj.satoken; -// -//import org.springframework.context.annotation.Bean; -//import org.springframework.context.annotation.Configuration; -//import org.springframework.context.annotation.Primary; -// -//import cn.dev33.satoken.config.SaTokenConfig; -// -///** -// * sa-token代码方式进行配置 -// */ -//@Configuration -//public class MySaTokenConfig { -// -// // 获取配置Bean +package com.pj.satoken; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +import cn.dev33.satoken.annotation.SaCheckInterceptor; + +/** + * sa-token代码方式进行配置 + */ +@Configuration +public class MySaTokenConfig extends WebMvcConfigurationSupport { + + // 获取配置Bean (以代码的方式配置sa-token) // @Primary // @Bean(name="MySaTokenConfig") // public SaTokenConfig getSaTokenConfig() { @@ -25,5 +25,11 @@ // config.setIsV(true); // 是否在初始化配置时打印版本字符画 // return config; // } -// -//} + + // 注册sa-token的拦截器,打开注解式鉴权功能 + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new SaCheckInterceptor()).addPathPatterns("/**"); + } + +} 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 064c60d4..c8bed11b 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 @@ -4,6 +4,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.session.SaSessionCustomUtil; import cn.dev33.satoken.stp.StpUtil; @@ -86,5 +88,21 @@ public class TestController { } + // 测试注解式鉴权, 浏览器访问: http://localhost:8081/test/at_check + @SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过 + @SaCheckPermission("user-add") // 注解式鉴权:当前会话必须具有指定权限才能通过 + @RequestMapping("at_check") + public AjaxJson at_check() { + System.out.println("======================= 进入方法,测试注解鉴权接口 ========================= "); + System.out.println("只有通过注解鉴权,才能进入此方法"); + return AjaxJson.getSuccess(); + } + + + @SaCheckLogin // 注解式鉴权:当前会话必须登录才能通过 + @RequestMapping("getInfo") + public String getInfo() { + return "用户信息"; + } } diff --git a/sa-token-dev/pom.xml b/sa-token-dev/pom.xml index 90a11e14..f9bfe2db 100644 --- a/sa-token-dev/pom.xml +++ b/sa-token-dev/pom.xml @@ -2,9 +2,12 @@ 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"> 4.0.0 + + cn.dev33 sa-token-dev - 0.0.1-SNAPSHOT + jar + 1.0.2 diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckInterceptor.java b/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckInterceptor.java new file mode 100644 index 00000000..6a9bc440 --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckInterceptor.java @@ -0,0 +1,72 @@ +package cn.dev33.satoken.annotation; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import cn.dev33.satoken.stp.StpUtil; + +/** + * 注解式鉴权 - 拦截器 + */ +public class SaCheckInterceptor implements HandlerInterceptor { + + // 每次请求之前触发 + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + // 获取处理method + if (handler instanceof HandlerMethod == false) { + return true; + } + HandlerMethod method = (HandlerMethod ) handler; + + // 验证登录 + if(method.hasMethodAnnotation(SaCheckLogin.class) || method.getBeanType().isAnnotationPresent(SaCheckLogin.class)) { + StpUtil.getLoginId(); + } + + // 获取权限注解 + SaCheckPermission scp = method.getMethodAnnotation(SaCheckPermission.class); + if(scp == null) { + scp = method.getBeanType().getAnnotation(SaCheckPermission.class); + } + if(scp == null) { + return true; + } + + // 开始验证权限 + Object[] codeArray = concatABC(scp.value(), scp.valueInt(), scp.valueLong()); + if(scp.isAnd()) { + StpUtil.checkPermissionAnd(codeArray); // 必须全部都有 + } else { + StpUtil.checkPermissionOr(codeArray); // 有一个就行了 + } + + return true; + } + + + // 合并三个数组 + private Object[] concatABC(String[] a, int[] b, long[] c) { + // 循环赋值 + Object[] d = new Object[a.length + b.length + c.length]; + for (int i = 0; i < a.length; i++) { + d[i] = a[i]; + } + for (int i = 0; i < b.length; i++) { + d[a.length + i] = b[i]; + } + for (int i = 0; i < c.length; i++) { + d[a.length + b.length + i] = c[i]; + } + return d; + } + + + + +} diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java b/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java new file mode 100644 index 00000000..48da60ef --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java @@ -0,0 +1,15 @@ +package cn.dev33.satoken.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标注一个路由方法,当前会话必须已登录才能通过 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface SaCheckLogin { + +} diff --git a/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java b/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java new file mode 100644 index 00000000..b5ec8b68 --- /dev/null +++ b/sa-token-dev/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java @@ -0,0 +1,39 @@ +package cn.dev33.satoken.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标注一个路由方法,当前会话必须具有指定权限才可以通过 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD,ElementType.TYPE}) +public @interface SaCheckPermission { + + /** + * 权限码数组 ,String类型 + * @return . + */ + String [] value() default {}; + + /** + * 权限码数组 ,int类型 + * @return . + */ + int [] valueInt() default {}; + + /** + * 权限码数组 ,long类型 + * @return . + */ + long [] valueLong() default {}; + + /** + * 是否属于and型验证 ,true=必须全部具有,false=只要具有一个就可以通过 + * @return . + */ + boolean isAnd() default true; + +} diff --git a/sa-token-doc/doc/README.md b/sa-token-doc/doc/README.md index de50ae43..bf5e8c27 100644 --- a/sa-token-doc/doc/README.md +++ b/sa-token-doc/doc/README.md @@ -19,6 +19,7 @@ - 持久层扩展(集成redis) - 多账号认证体系(比如一个商城项目的user表和admin表) - 无cookie模式(APP、小程序等前后台分离场景) +- 注解式鉴权(优雅的将鉴权与业务代码分离) - 零配置与Spring等框架集成 - ... diff --git a/sa-token-doc/doc/_sidebar.md b/sa-token-doc/doc/_sidebar.md index b79b83e3..a592e505 100644 --- a/sa-token-doc/doc/_sidebar.md +++ b/sa-token-doc/doc/_sidebar.md @@ -14,6 +14,7 @@ - [无cookie模式](/use/not-cookie) - [模拟他人](/use/mock-person) - [多账号验证](/use/many-account) + - [注解式鉴权](/use/at-check) - [框架配置](/use/config) - **其它** diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index f90bd305..1f5fd244 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -7,7 +7,7 @@ - +