parent
6bfb8925a0
commit
6ef15f97db
|
@ -37,7 +37,9 @@ module.exports = {
|
|||
collapsable: true,
|
||||
sidebarDepth: 2,
|
||||
children: [
|
||||
|
||||
['/guide/diboot-shiro/安装', '安装'],
|
||||
['/guide/diboot-shiro/权限设置', '权限设置'],
|
||||
['/guide/diboot-shiro/权限缓存', '权限缓存'],
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -61,7 +63,7 @@ module.exports = {
|
|||
text: '学习',
|
||||
items: [
|
||||
{text: 'diboot-core指南', link: '/guide/diboot-core/安装'},
|
||||
{text: 'diboot-shiro指南', link: '/guide/diboot-shiro/'},
|
||||
{text: 'diboot-shiro指南', link: '/guide/diboot-shiro/安装'},
|
||||
{text: 'diboot-devtools指南', link: '/guide/diboot-devtools/安装'}
|
||||
]
|
||||
}, {
|
||||
|
@ -70,7 +72,7 @@ module.exports = {
|
|||
{text: 'diboot-core', link: '/api/diboot-core/'}
|
||||
]
|
||||
},{
|
||||
text: '1.x', link: 'https://diboot.com'
|
||||
text: '1.x', link: 'https://www.diboot.com'
|
||||
}, {
|
||||
text: 'GitHub', link: 'https://github.com/dibo-software/diboot-v2'
|
||||
}]
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
# 安装
|
||||
|
||||
## diboot-shiro是什么?
|
||||
|
||||
> diboot-shiro是一款权限认证框架,基于开源Shiro安全框架进行二次开发
|
||||
|
||||
* 采用当前流行的前后端分离架构,基于jwt认证模式;
|
||||
* 默认提供`账号密码` 认证, 后续扩展组件包括:`企业微信`、`微信`等认证方式;
|
||||
* 基于shiro细颗粒权限二次开发,通过简单的配置,系统中权限可自动写入数据库;
|
||||
* 基于shiro内存缓存,系统操作权限后无须重启,自动更新缓存权限为最新;
|
||||
|
||||
## 引入依赖
|
||||
|
||||
> 目前diboot-shiro存放与diboot私有仓库,使用时需要添加私有仓库地址
|
||||
|
||||
* Gradle项目
|
||||
1. 添加仓库地址
|
||||
在`build.gradle`的`repositories`配置项中添加仓库地址
|
||||
```groovy
|
||||
repositories {
|
||||
maven{ url 'http://maven.diboot.com/repository/devtools/'}
|
||||
}
|
||||
```
|
||||
2. 引入依赖
|
||||
```groovy
|
||||
compile ("com.diboot:diboot-shiro:2.0.1")
|
||||
```
|
||||
|
||||
* Maven项目
|
||||
1. 添加仓库地址
|
||||
在`pom.xml`的`repositories`标签中添加仓库地址
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>diboot-devtools</id>
|
||||
<url>http://maven.diboot.com/repository/devtools/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
```
|
||||
2. 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.diboot</groupId>
|
||||
<artifactId>diboot-shiro</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
```
|
|
@ -0,0 +1,32 @@
|
|||
# 权限缓存
|
||||
|
||||
> diboot-shiro的权限缓存基于shiro自带的内存缓存进行二次开发
|
||||
|
||||
### 缓存配置
|
||||
```properties
|
||||
#是否开启缓存:默认false
|
||||
diboot.shiro.cache.permission-caching-enabled=true
|
||||
#缓存的方式:memory
|
||||
diboot.shiro.cache.cache-way=memory
|
||||
```
|
||||
::: tip
|
||||
注:暂时只支持内存缓存,redis已经纳入开发计划
|
||||
:::
|
||||
|
||||
### 缓存注解
|
||||
#### @AuthorizationCache
|
||||
|
||||
> 在资源授权校验过程中,系统会频繁与数据库进行交互,故而提供缓存机制。shiro的缓存,仅仅是将登陆时候的将用户缓存记录下来,
|
||||
当用户更改了权限的时候,用户需要重新登陆权限才会生效。
|
||||
|
||||
#### 特点
|
||||
> * 易开发:注解只需要加在操作权限的接口上
|
||||
> * 操作简化:发生权限操作之后,将自动清空权限缓存,无须重新登陆
|
||||
|
||||
#### 示例
|
||||
```java
|
||||
@GetMapping("/list")
|
||||
@AuthorizationCache
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("list"), name = "列表")
|
||||
public JsonResult getList(){}
|
||||
```
|
|
@ -0,0 +1,125 @@
|
|||
# 权限设置
|
||||
|
||||
> diboot-shiro是基于shiro注解@RequiresPermissions封装的细颗粒权限控制,丰富了注解的内容,更加方便权限的配置和管理。
|
||||
|
||||
|
||||
## 权限配置
|
||||
|
||||
```properties
|
||||
#是否存储数据库:默认false 不开启
|
||||
diboot.shiro.auth.storage=true
|
||||
|
||||
#存储环境:{dev, test, prod}
|
||||
# 默认dev环境,不会删除代码中不存在的权限,多人协作开发时,需要开启,否则回删除对方新增的权限
|
||||
diboot.shiro.auth.env=dev
|
||||
|
||||
#配置所有权限均可访问的角色
|
||||
diboot.shiro.auth.has-all-permissions-role-list[0]=ALL1
|
||||
diboot.shiro.auth.has-all-permissions-role-list[1]=ALL2
|
||||
```
|
||||
> `diboot.shiro.auth.has-all-permissions-role-list`配置可访问任意接口的权限,如果不配置,默认是角色`ADMIN`
|
||||
|
||||
## 权限注解
|
||||
|
||||
### @AuthorizationPrefix
|
||||
|
||||
>- @AuthorizationPrefix 和 @AuthorizationWrapper 需要搭配一起使用;
|
||||
>- @AuthorizationPrefix 类注解,用于`标记类`、设置`权限前缀`等,作用当前类的所有方法;
|
||||
|
||||
### @AuthorizationWrapper
|
||||
>- @AuthorizationWrapper 类/方法注解,包装@RequiresPermissions注解,使用方式与之类似,扩展了`权限名称`、`权限前缀`
|
||||
>- @AuthorizationWrapper 方法上使用可以覆盖类上的权限配置
|
||||
|
||||
## 注解示例
|
||||
#### 示例1:
|
||||
```java
|
||||
/**
|
||||
* 访问当前类的所有方法都需要具备`authorizationClass:global`权限
|
||||
*/
|
||||
@AuthorizationPrefix(name = "前缀", code = "authorizationClass", prefix = "authorizationClass")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("global"), name = "全局权限")
|
||||
public class AuthorizationWrapperClassController {
|
||||
|
||||
}
|
||||
```
|
||||
::: tip
|
||||
`@AuthorizationPrefix`的`name`和`code`属性用于管理后台标记和展示,若开启数据库存储,那么将写入数据库;
|
||||
|
||||
`@AuthorizationPrefix`的`prefix`将作为当前类的权限前缀进行设置;
|
||||
|
||||
`@AuthorizationWrapper`的`value`对应`shiro`的`@RequiresPermissions`注解,将自动拼接前缀;
|
||||
|
||||
`@AuthorizationWrapper`的`name`标注当前权限的名称;
|
||||
:::
|
||||
|
||||
#### 示例2:
|
||||
```java
|
||||
/**
|
||||
* test1方法覆盖了`authorizationClass:global`权限,需要`authorizationClass:test1`权限访问
|
||||
*/
|
||||
@AuthorizationPrefix(name = "前缀", code = "authorizationClass", prefix = "authorizationClass")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("global"), name = "全局权限")
|
||||
public class AuthorizationWrapperClassController {
|
||||
|
||||
@GetMapping("/test1")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("test1"), name = "测试1")
|
||||
public JsonResult test1() {}
|
||||
}
|
||||
```
|
||||
#### 示例3:
|
||||
```java
|
||||
/**
|
||||
* test2方法的访问权限为`test`
|
||||
*/
|
||||
@AuthorizationPrefix(name = "前缀", code = "authorizationClass", prefix = "authorizationClass")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("global"), name = "全局权限")
|
||||
public class AuthorizationWrapperClassController {
|
||||
|
||||
@GetMapping("/test2")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("test2"), name = "测试2", ignorePrefix = true)
|
||||
public JsonResult test2() {}
|
||||
}
|
||||
```
|
||||
::: tip
|
||||
`@AuthorizationWrapper`的`ignorePrefix`表示是否忽略前缀,默认`false`,表示不忽略。
|
||||
:::
|
||||
|
||||
#### 示例4:
|
||||
```java
|
||||
/**
|
||||
* test3方法访问权限为:custom:test3
|
||||
*/
|
||||
@AuthorizationPrefix(name = "前缀", code = "authorizationClass", prefix = "authorizationClass")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("global"), name = "全局权限")
|
||||
public class AuthorizationWrapperClassController {
|
||||
|
||||
@GetMapping("/test3")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("test3"), name = "测试3", prefix = "custom")
|
||||
public JsonResult test3() {}
|
||||
}
|
||||
```
|
||||
::: tip
|
||||
`@AuthorizationWrapper`的`prefix`也表示前缀,优先级高于`@AuthorizationPrefix`的`prefix`,设置之后产生覆盖效果
|
||||
:::
|
||||
|
||||
#### 示例5:
|
||||
```java
|
||||
/**
|
||||
* test3方法访问权限为:custom:test3
|
||||
*/
|
||||
@AuthorizationPrefix(name = "前缀", code = "authorizationClass", prefix = "authorizationClass")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("global"), name = "全局权限")
|
||||
public class AuthorizationWrapperClassController {
|
||||
|
||||
@GetMapping("/test4or5")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions(value = {"test4", "test5"}, logical = Logical.AND),
|
||||
name = {"测试4", "测试5"})
|
||||
public JsonResult test4or5() {
|
||||
return new JsonResult();
|
||||
}
|
||||
}
|
||||
```
|
||||
::: tip
|
||||
`@AuthorizationWrapper`的name对应的是数组类型,与`@RequiresPermissions#value`设置的权限为对应关系。
|
||||
:::
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationPrefix;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 权限测试
|
||||
* @author : wee
|
||||
* @version : v 2.0
|
||||
* @Date 2019-06-19 13:37
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/authorizationClass")
|
||||
@AuthorizationPrefix(name = "前缀", code = "authorizationClass", prefix = "authorizationClass")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("global"), name = "全局权限")
|
||||
public class AuthorizationWrapperClassController {
|
||||
|
||||
/**
|
||||
* 全局权限:authorizationClass:global
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/test")
|
||||
public JsonResult test() {
|
||||
return new JsonResult();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 自定义权限1:authorizationClass:test1
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/test1")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("test1"), name = "测试1")
|
||||
public JsonResult test1() {
|
||||
return new JsonResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义权限2:test2
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/test2")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("test2"), name = "测试2", ignorePrefix = true)
|
||||
public JsonResult test2() {
|
||||
return new JsonResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义权限3:custom:test3
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/test3")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("test3"), name = "测试3", prefix = "custom")
|
||||
public JsonResult test3() {
|
||||
return new JsonResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义权限4:同时满足 authorizationClass:test3 and authorizationClass:test4
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/test4or5")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions(value = {"test4", "test5"}, logical = Logical.AND),
|
||||
name = {"测试4", "测试5"})
|
||||
public JsonResult test4or5() {
|
||||
return new JsonResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/test6")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions(value = "test7"),
|
||||
name = "测试7")
|
||||
public JsonResult test6() {
|
||||
return new JsonResult();
|
||||
}
|
||||
}
|
|
@ -32,9 +32,6 @@ import java.util.stream.Collectors;
|
|||
* {@link AuthorizationStorage}中封装了将{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper}权限自动入库的操作,
|
||||
* <strong>注:权限入库每个Controller需要加上类注解{@link AuthorizationPrefix}用于识别</strong>
|
||||
* <br/>
|
||||
* 当你使用注解{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper}, 且需要自动让权限入库,请实现{@link ApplicationListener}并注入该类,
|
||||
* <br/>
|
||||
* 调用类中方法{@link AuthorizationStorage#autoStorage(ApplicationContext)}
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-27 10:01
|
||||
|
|
|
@ -1,29 +1,23 @@
|
|||
package com.diboot.example.listener;
|
||||
package com.diboot.shiro.authz.storage;
|
||||
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.authz.storage.AuthorizationStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 示例监听器,权限入库
|
||||
* 权限入库
|
||||
* @author : wee
|
||||
* @version : v 2.0
|
||||
* @Date 2019-06-18 23:11
|
||||
* @version : v1.0
|
||||
* @Date 2019-08-28 10:44
|
||||
*/
|
||||
@Component
|
||||
public class ExampleListener implements ApplicationListener<ContextRefreshedEvent> {
|
||||
public class StorageListener implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
@Autowired
|
||||
private AuthorizationStorage authorizationStorage;
|
||||
|
||||
/**
|
||||
* Handle an application event.
|
||||
*
|
||||
* @param event the event to respond to
|
||||
*/
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
if (V.isEmpty(event.getApplicationContext().getParent())) {
|
|
@ -1,48 +1,23 @@
|
|||
package com.diboot.shiro.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/***
|
||||
* 认证方式
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthType {
|
||||
|
||||
USERNAME_PASSWORD(1, true, "账号密码"),
|
||||
WX_MP(2, false, "公众号"),
|
||||
WX_CP(3, false, "企业微信");
|
||||
|
||||
private AuthType(int code, boolean requirePassword, String label){
|
||||
this.code = code;
|
||||
this.requirePassword = requirePassword;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private int code;
|
||||
private boolean requirePassword;
|
||||
private String label;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public boolean isRequirePassword() {
|
||||
return requirePassword;
|
||||
}
|
||||
|
||||
public void setRequirePassword(boolean requirePassword) {
|
||||
this.requirePassword = requirePassword;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue