Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # diboot-example/src/main/java/com/diboot/example/controller/OrganizationController.java # diboot-example/src/main/java/com/diboot/example/controller/SysUserController.java # diboot-shiro/src/main/java/com/diboot/shiro/controller/RoleController.java
This commit is contained in:
commit
9fdeda639d
10
README.md
10
README.md
|
@ -35,6 +35,11 @@ RBAC的角色权限+基于Shiro的细粒度权限控制
|
|||
#### 2、@AuthorizationWrapper
|
||||
类/方法注解,在保证shiro的@RequirePermissions注解的功能基础上,增加名称、权限前缀特性,使用方式同@RequiresPermissions
|
||||
|
||||
#### 3、@AuthorizationCache
|
||||
方法注解,在资源授权校验过程中,系统会频繁与数据库进行交互,故而提供缓存机制
|
||||
* 缓存时机:缓存会在用户第一次进行权限验证的之后缓存数据
|
||||
* 当前注解作用:如果通过系统调整权限,只需要将该注解加在更新或添加权限处,将会清空权限缓存,下次进入将重新加载权限
|
||||
|
||||
#### 3、AuthorizationProperties
|
||||
提供一些权限相关的配置,主要包括:
|
||||
- 权限环境变量:提供dev、test、prod三种选项
|
||||
|
@ -54,6 +59,11 @@ 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[2]=ALL3
|
||||
#配置权限缓存机制
|
||||
##是否开启缓存
|
||||
diboot.shiro.cache.permission-caching-enabled=true
|
||||
##缓存方式:暂时提供shiro内置的内存缓存
|
||||
diboot.shiro.cache.cache-way=memory
|
||||
```
|
||||
|
||||
#### 4、AuthorizationStorage
|
||||
|
|
|
@ -163,8 +163,8 @@ public class DepartmentController extends BaseCrudRestController {
|
|||
/*
|
||||
* 根据组织ID获取部门kv list
|
||||
* */
|
||||
@GetMapping("/getDepartment/{orgId}")
|
||||
public JsonResult getDepartment(@PathVariable Long orgId, HttpServletRequest request){
|
||||
@GetMapping("/getDepartmentKV/{orgId}")
|
||||
public JsonResult getDepartmentKV(@PathVariable Long orgId, HttpServletRequest request){
|
||||
Wrapper wrapper = null;
|
||||
//获取部门KV
|
||||
wrapper = new QueryWrapper<Department>()
|
||||
|
@ -176,6 +176,21 @@ public class DepartmentController extends BaseCrudRestController {
|
|||
return new JsonResult(deptKvList);
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据组织ID获取部门list
|
||||
* */
|
||||
@GetMapping("/getDepartmentList/{orgId}")
|
||||
public JsonResult getDepartmentList(@PathVariable Long orgId, HttpServletRequest request) throws Exception {
|
||||
// 构建分页
|
||||
Pagination pagination = buildPagination(request);
|
||||
Wrapper wrapper = new QueryWrapper<Department>()
|
||||
.lambda()
|
||||
.eq(Department::getOrgId, orgId);
|
||||
List<DepartmentVO> voList = departmentService.getViewObjectList(wrapper, pagination, DepartmentVO.class);
|
||||
|
||||
return new JsonResult(voList);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return departmentService;
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.diboot.core.binding.RelationsBinder;
|
|||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.service.DictionaryService;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
|
@ -36,12 +37,13 @@ public class OrganizationController extends BaseCrudRestController {
|
|||
private DictionaryService dictionaryService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public JsonResult getVOList(Organization organization, Pagination pagination, HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Organization> queryWrapper = super.buildQueryWrapper(organization);
|
||||
public JsonResult getVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Organization> queryWrapper = buildQuery(request);
|
||||
queryWrapper.lambda().eq(Organization::getParentId, 0);
|
||||
// 构建分页
|
||||
Pagination pagination = buildPagination(request);
|
||||
// 查询当前页的Entity主表数据
|
||||
List<Organization> entityList = organizationService.getEntityList(queryWrapper, pagination);
|
||||
//筛选出在列表页展示的字段
|
||||
List<OrganizationVO> voList = RelationsBinder.convertAndBind(entityList, OrganizationVO.class);
|
||||
List<OrganizationVO> voList = organizationService.getOrganizatioList(queryWrapper, pagination);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, voList).bindPagination(pagination);
|
||||
}
|
||||
|
@ -83,10 +85,11 @@ public class OrganizationController extends BaseCrudRestController {
|
|||
@GetMapping("/attachMore")
|
||||
public JsonResult attachMore(HttpServletRequest request, ModelMap modelMap){
|
||||
Wrapper wrapper = null;
|
||||
//获取组织机构KV
|
||||
//获取父组织机构KV
|
||||
wrapper = new QueryWrapper<Organization>()
|
||||
.lambda()
|
||||
.select(Organization::getName, Organization::getId);
|
||||
.select(Organization::getName, Organization::getId)
|
||||
.eq(Organization::getParentId, 0);
|
||||
List<KeyValue> orgKvList = organizationService.getKeyValueList(wrapper);
|
||||
modelMap.put("orgKvList", orgKvList);
|
||||
|
||||
|
@ -97,6 +100,25 @@ public class OrganizationController extends BaseCrudRestController {
|
|||
return new JsonResult(modelMap);
|
||||
}
|
||||
|
||||
@GetMapping("/getOrgTree")
|
||||
public JsonResult getOrgTree() throws Exception{
|
||||
QueryWrapper<Organization> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.lambda().eq(Organization::getParentId, 0);
|
||||
List<Organization> orgList = organizationService.getEntityList(queryWrapper);
|
||||
List<OrganizationVO> voList = RelationsBinder.convertAndBind(orgList, OrganizationVO.class);
|
||||
if(V.notEmpty(voList)){
|
||||
for(OrganizationVO vo : voList){
|
||||
queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.lambda()
|
||||
.eq(Organization::getParentId, vo.getId());
|
||||
List<Organization> childList = organizationService.getEntityList(queryWrapper);
|
||||
List<OrganizationVO> childvVoList = RelationsBinder.convertAndBind(childList, OrganizationVO.class);
|
||||
vo.setChildren(childvVoList);
|
||||
}
|
||||
}
|
||||
return new JsonResult(orgList);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return organizationService;
|
||||
|
|
|
@ -114,8 +114,8 @@ public class PositionController extends BaseCrudRestController {
|
|||
/*
|
||||
* 根据部门ID获取职位kv list
|
||||
* */
|
||||
@GetMapping("/getPosition/{deptId}")
|
||||
public JsonResult getPosition(@PathVariable Long deptId, HttpServletRequest request){
|
||||
@GetMapping("/getPositionKV/{deptId}")
|
||||
public JsonResult getPositionKV(@PathVariable Long deptId, HttpServletRequest request){
|
||||
Wrapper wrapper = null;
|
||||
List<Long> positionIdList = new ArrayList<>();
|
||||
wrapper = new LambdaQueryWrapper<PositionDepartment>()
|
||||
|
|
|
@ -18,10 +18,15 @@ import com.diboot.example.service.DepartmentService;
|
|||
import com.diboot.example.service.SysUserService;
|
||||
import com.diboot.example.vo.SysUserListVO;
|
||||
import com.diboot.example.vo.SysUserVO;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationPrefix;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
import com.diboot.shiro.service.PermissionService;
|
||||
import com.diboot.shiro.service.RoleService;
|
||||
import com.diboot.shiro.util.JwtHelper;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -34,6 +39,7 @@ import java.util.List;
|
|||
|
||||
@RestController
|
||||
@RequestMapping("/sysUser")
|
||||
@AuthorizationPrefix(name = "用户管理", code = "sysUser", prefix = "sysUser")
|
||||
public class SysUserController extends BaseCrudRestController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysUserController.class);
|
||||
|
@ -47,12 +53,19 @@ public class SysUserController extends BaseCrudRestController {
|
|||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private DepartmentService departmentService;
|
||||
|
||||
|
||||
@GetMapping("/list")
|
||||
public JsonResult getVOList(SysUser sysUser, Pagination pagination, HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<SysUser> queryWrapper = super.buildQueryWrapper(sysUser);
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("list"), name = "列表")
|
||||
public JsonResult getVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<SysUser> queryWrapper = buildQuery(request);
|
||||
// 构建分页
|
||||
Pagination pagination = buildPagination(request);
|
||||
// 查询当前页的Entity主表数据
|
||||
List<SysUserVO> voList = sysUserService.getSysUserList(queryWrapper, pagination);
|
||||
//筛选出在列表页展示的字段
|
||||
|
@ -67,6 +80,7 @@ public class SysUserController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("create"), name = "新建")
|
||||
public JsonResult createEntity(@RequestBody SysUser entity, BindingResult result, HttpServletRequest request)
|
||||
throws Exception{
|
||||
boolean success = sysUserService.createSysUser(entity);
|
||||
|
@ -85,6 +99,7 @@ public class SysUserController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("update"), name = "更新")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @RequestBody SysUser entity, BindingResult result,
|
||||
HttpServletRequest request) throws Exception{
|
||||
// Model属性值验证结果
|
||||
|
@ -107,6 +122,7 @@ public class SysUserController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("read"), name = "读取")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
SysUserVO sysUserVO = sysUserService.getSysUser(id);
|
||||
|
@ -120,6 +136,7 @@ public class SysUserController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("delete"), name = "删除")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
boolean success = sysUserService.deleteSysUser(id);
|
||||
if(success){
|
||||
|
@ -215,7 +232,16 @@ public class SysUserController extends BaseCrudRestController {
|
|||
|
||||
List<RoleVO> roleVOList = roleService.getRelatedRoleAndPermissionListByUser(SysUser.class.getSimpleName(), user.getId());
|
||||
if (V.isEmpty(roleVOList)){
|
||||
return new JsonResult(Status.FAIL_OPERATION, new String[]{"获取用户角色失败"});
|
||||
return new JsonResult(Status.FAIL_OPERATION, new String[]{"用户未配置角色,获取数据失败"});
|
||||
}
|
||||
|
||||
// 如果具有管理员角色,则赋予所有权限
|
||||
for (RoleVO roleVO : roleVOList){
|
||||
if (roleVO.isAdmin()){
|
||||
List<Permission> allPermissionList = permissionService.getEntityList(null);
|
||||
roleVO.setPermissionList(allPermissionList);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
user.setRoleVOList(roleVOList);
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.vo.OrganizationVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 单位相关Service
|
||||
|
@ -11,4 +16,6 @@ import com.diboot.example.entity.Organization;
|
|||
*/
|
||||
public interface OrganizationService extends BaseService<Organization> {
|
||||
|
||||
List<OrganizationVO> getOrganizatioList(Wrapper wrapper, Pagination pagination);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.diboot.core.binding.RelationsBinder;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.mapper.OrganizationMapper;
|
||||
import com.diboot.example.service.OrganizationService;
|
||||
import com.diboot.example.vo.OrganizationVO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 单位相关Service实现
|
||||
* @author Mazhicheng
|
||||
|
@ -17,4 +25,17 @@ import org.springframework.stereotype.Service;
|
|||
@Slf4j
|
||||
public class OrganizationServiceImpl extends BaseServiceImpl<OrganizationMapper, Organization> implements OrganizationService {
|
||||
|
||||
@Override
|
||||
public List<OrganizationVO> getOrganizatioList(Wrapper wrapper, Pagination pagination) {
|
||||
List<OrganizationVO> voList = super.getViewObjectList(wrapper, pagination, OrganizationVO.class);
|
||||
if(V.notEmpty(voList)){
|
||||
for(OrganizationVO vo : voList){
|
||||
wrapper = new LambdaQueryWrapper<Organization>().eq(Organization::getParentId, vo.getId());
|
||||
List<Organization> orgList = super.getEntityList(wrapper);
|
||||
List<OrganizationVO> orgVoList = RelationsBinder.convertAndBind(orgList, OrganizationVO.class);
|
||||
vo.setChildren(orgVoList);
|
||||
}
|
||||
}
|
||||
return voList;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import com.diboot.core.binding.annotation.BindField;
|
|||
import com.diboot.example.entity.Organization;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wangyongliang
|
||||
* @version v2.0
|
||||
|
@ -22,4 +24,6 @@ public class OrganizationVO extends Organization {
|
|||
@BindDict(type = "INDUSTRY", field = "industry")
|
||||
private String industryLabel;
|
||||
|
||||
private List<OrganizationVO> children;
|
||||
|
||||
}
|
|
@ -98,6 +98,10 @@ 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[2]=ALL3
|
||||
|
||||
#权限缓存机制
|
||||
diboot.shiro.cache.permission-caching-enabled=true
|
||||
diboot.shiro.cache.cache-way=memory
|
||||
|
||||
#------web页面访问的时候需要如下配置----
|
||||
spring.mvc.view.prefix=/static
|
||||
spring.mvc.view.suffix=.html
|
|
@ -5,6 +5,7 @@ dependencies {
|
|||
|
||||
// compile("org.springframework.boot:spring-boot-configuration-processor")
|
||||
compile("org.apache.shiro:shiro-spring:1.4.1")
|
||||
compile("org.aspectj:aspectjweaver")
|
||||
compile("com.auth0:java-jwt:3.4.1",
|
||||
"io.jsonwebtoken:jjwt:0.9.1")
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.shiro.authz.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 权限缓存
|
||||
* <p>
|
||||
* 缓存目的:在资源授权校验过程中,系统会频繁与数据库进行交互,故而提供缓存机制<br/>
|
||||
* 缓存时机:缓存会在用户第一次进行权限验证的之后缓存数据
|
||||
* 当前注解作用:如果通过系统调整角色的权限,只需要将该注解加在更新或添加权限处,将会清空缓存,下次进入将重新加载
|
||||
* </p>
|
||||
* @author : wee
|
||||
* @version v1.0
|
||||
* @Date 2019-07-23 09:27
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface AuthorizationCache {
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.diboot.shiro.authz.aspect;
|
||||
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationCache;
|
||||
import com.diboot.shiro.jwt.BaseJwtRealm;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.cache.Cache;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
import org.apache.tomcat.util.http.parser.Authorization;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 当有操作的时候,自动更新被注解的相关数据
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-07-24 23:20
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class CacheHandler{
|
||||
|
||||
private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = ".authorizationCache";
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
/**
|
||||
* 设置切片
|
||||
*/
|
||||
@Pointcut("@annotation(com.diboot.shiro.authz.annotation.AuthorizationCache)")
|
||||
public void proxyAspect() {}
|
||||
|
||||
/**
|
||||
* 当请求{@link AuthorizationCache}注解的方法执行完成后,自动触发此处切面
|
||||
* 作用:重新缓存权限和方法
|
||||
* @param joinPoint
|
||||
*/
|
||||
@AfterReturning("proxyAspect()")
|
||||
public void afterReturning(JoinPoint joinPoint) {
|
||||
try {
|
||||
log.info("【修改权限】==> 正在调用【{}#{}()】方法修改!", joinPoint.getThis().getClass(), joinPoint.getSignature().getName());
|
||||
Cache<Object, Authorization> cache = cacheManager.getCache(BaseJwtRealm.class.getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX);
|
||||
//统一删除所有的缓存,所有用户需重新加载缓存
|
||||
if (V.notEmpty(cache) && cache.size() > 0) {
|
||||
cache.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.info("【修改权限】==> 调用【{}#{}()】异常:", joinPoint.getThis().getClass(), joinPoint.getSignature().getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
26
diboot-shiro/src/main/java/com/diboot/shiro/authz/cache/MemoryCondition.java
vendored
Normal file
26
diboot-shiro/src/main/java/com/diboot/shiro/authz/cache/MemoryCondition.java
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package com.diboot.shiro.authz.cache;
|
||||
|
||||
import com.diboot.shiro.authz.properties.AuthCacheProperties;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* memory条件类:用与创建memory缓存对象
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-08-05 14:39
|
||||
*/
|
||||
public class MemoryCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
//获取配置信息
|
||||
Boolean enableCached = context.getEnvironment().getProperty(AuthCacheProperties.CACHE_PREFIX + ".permission-caching-enabled", Boolean.class);
|
||||
enableCached = enableCached == null ? false : enableCached;
|
||||
AuthCacheProperties.CacheWay cacheWay = context.getEnvironment().getProperty(AuthCacheProperties.CACHE_PREFIX + ".cache-way", AuthCacheProperties.CacheWay.class);
|
||||
cacheWay = cacheWay == null ? AuthCacheProperties.CacheWay.MEMORY : cacheWay;
|
||||
return enableCached && AuthCacheProperties.CacheWay.MEMORY.equals(cacheWay);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.diboot.shiro.authz.cache;
|
||||
|
||||
import org.apache.shiro.cache.Cache;
|
||||
import org.apache.shiro.cache.CacheException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* TODO redis缓存处理,等候完善
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-08-05 16:20
|
||||
*/
|
||||
public class RedisCache<K, V> implements Cache<K, V> {
|
||||
@Override
|
||||
public V get(K k) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K k, V v) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(K k) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() throws CacheException {
|
||||
//TODO 根据模糊key获取redis中所有的权限,然后统一清空
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
//TODO 模糊key获取redis所有当前系统中的权限
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return null;
|
||||
}
|
||||
}
|
28
diboot-shiro/src/main/java/com/diboot/shiro/authz/cache/RedisCacheManager.java
vendored
Normal file
28
diboot-shiro/src/main/java/com/diboot/shiro/authz/cache/RedisCacheManager.java
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package com.diboot.shiro.authz.cache;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.cache.Cache;
|
||||
import org.apache.shiro.cache.CacheException;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
import org.apache.shiro.util.Destroyable;
|
||||
|
||||
/**
|
||||
* TODO redis缓存管理:暂时不提供
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-08-05 16:15
|
||||
*/
|
||||
@Slf4j
|
||||
public class RedisCacheManager implements CacheManager, Destroyable {
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> getCache(String s) throws CacheException {
|
||||
log.error("【缓存】<== 尚未实现redis缓存,暂时不可用,请选择内存缓存");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
//清除redis内容
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.diboot.shiro.authz.cache;
|
||||
|
||||
import com.diboot.shiro.authz.properties.AuthCacheProperties;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* redis条件类:用与创建redis缓存对象
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-08-05 14:35
|
||||
*/
|
||||
public class RedisCondition implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
//获取配置信息
|
||||
Boolean enableCached = context.getEnvironment().getProperty(AuthCacheProperties.CACHE_PREFIX + ".permission-caching-enabled", Boolean.class);
|
||||
enableCached = enableCached == null ? false : enableCached;
|
||||
AuthCacheProperties.CacheWay cacheWay = context.getEnvironment().getProperty(AuthCacheProperties.CACHE_PREFIX + ".cache-way", AuthCacheProperties.CacheWay.class);
|
||||
return enableCached && AuthCacheProperties.CacheWay.REDIS.equals(cacheWay);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package com.diboot.shiro.authz.config;
|
||||
|
||||
import com.diboot.shiro.authz.properties.AuthorizationProperties;
|
||||
import com.diboot.shiro.authz.properties.AuthCacheProperties;
|
||||
import com.diboot.shiro.authz.storage.AuthorizationStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* 权限配置
|
||||
|
@ -15,7 +15,7 @@ import org.springframework.core.annotation.Order;
|
|||
* @Date 2019-06-27 10:30
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(AuthorizationProperties.class)
|
||||
@EnableConfigurationProperties({AuthorizationProperties.class, AuthCacheProperties.class})
|
||||
public class AuthorizationAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package com.diboot.shiro.authz.properties;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-07-29 15:59
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(AuthCacheProperties.CACHE_PREFIX)
|
||||
public class AuthCacheProperties {
|
||||
|
||||
public final static String CACHE_PREFIX = "diboot.shiro.cache";
|
||||
|
||||
/**
|
||||
* 是否开启权限缓存:默认false
|
||||
*/
|
||||
private boolean permissionCachingEnabled = false;
|
||||
|
||||
/**
|
||||
* 缓存方式:默认内存缓存
|
||||
*/
|
||||
private CacheWay cacheWay = CacheWay.MEMORY;
|
||||
|
||||
/**
|
||||
* 缓存方式
|
||||
* <p>
|
||||
* 当前提供本地缓存
|
||||
* </p>
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CacheWay {
|
||||
/**
|
||||
* 内存缓存
|
||||
*/
|
||||
MEMORY,
|
||||
/**
|
||||
* redis缓存: TODO 尚未实现,暂不可用
|
||||
*/
|
||||
@Deprecated
|
||||
REDIS;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,13 +4,12 @@ import lombok.AllArgsConstructor;
|
|||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限入库配置文件
|
||||
*
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-27 10:16
|
||||
|
@ -19,26 +18,38 @@ import java.util.List;
|
|||
@ConfigurationProperties(prefix = "diboot.shiro.auth")
|
||||
public class AuthorizationProperties {
|
||||
|
||||
/**设置权限存储的环境:其中开发环境权限不会替换删除,测试和生产会替换删除*/
|
||||
/**
|
||||
* 设置权限存储的环境:其中开发环境权限不会替换删除,测试和生产会替换删除
|
||||
*/
|
||||
private EnvEnum env = EnvEnum.DEV;
|
||||
|
||||
/**是否开启存储权限*/
|
||||
/**
|
||||
* 是否开启存储权限
|
||||
*/
|
||||
private boolean storage = false;
|
||||
|
||||
/**具有所有权限的角色*/
|
||||
/**
|
||||
* 具有所有权限的角色
|
||||
*/
|
||||
private List<String> hasAllPermissionsRoleList;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum EnvEnum {
|
||||
public enum EnvEnum {
|
||||
|
||||
/**生产环境*/
|
||||
/**
|
||||
* 生产环境
|
||||
*/
|
||||
PROD("prod"),
|
||||
|
||||
/**测试环境*/
|
||||
/**
|
||||
* 测试环境
|
||||
*/
|
||||
TEST("test"),
|
||||
|
||||
/**开发环境*/
|
||||
/**
|
||||
* 开发环境
|
||||
*/
|
||||
DEV("dev");
|
||||
|
||||
private String env;
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
package com.diboot.shiro.config;
|
||||
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.authz.aop.CustomAuthorizationAttributeSourceAdvisor;
|
||||
import com.diboot.shiro.authz.cache.MemoryCondition;
|
||||
import com.diboot.shiro.authz.cache.RedisCacheManager;
|
||||
import com.diboot.shiro.authz.cache.RedisCondition;
|
||||
import com.diboot.shiro.authz.properties.AuthorizationProperties;
|
||||
import com.diboot.shiro.authz.properties.AuthCacheProperties;
|
||||
import com.diboot.shiro.jwt.BaseJwtAuthenticationFilter;
|
||||
import com.diboot.shiro.jwt.BaseJwtRealm;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.realm.Realm;
|
||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||
|
@ -14,8 +21,10 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
|
||||
|
@ -30,16 +39,47 @@ import java.util.Map;
|
|||
* @date 2019/6/6
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(AuthorizationProperties.class)
|
||||
@AutoConfigureAfter(AuthCacheProperties.class)
|
||||
@EnableConfigurationProperties({AuthorizationProperties.class, AuthCacheProperties.class})
|
||||
public class ShiroConfig {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
|
||||
|
||||
@Autowired
|
||||
private AuthorizationProperties authorizationProperties;
|
||||
|
||||
@Autowired
|
||||
private AuthCacheProperties authCacheProperties;
|
||||
|
||||
/**
|
||||
* 将数据缓存到内存中
|
||||
* @return
|
||||
*/
|
||||
@Bean("cacheManager")
|
||||
@Conditional(MemoryCondition.class)
|
||||
public CacheManager memoryCacheManager() {
|
||||
return new MemoryConstrainedCacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据存储到redis缓存
|
||||
* @return
|
||||
*/
|
||||
@Bean("cacheManager")
|
||||
@Conditional(RedisCondition.class)
|
||||
public CacheManager redisCacheManager() {
|
||||
return new RedisCacheManager();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public Realm realm(){
|
||||
BaseJwtRealm realm = new BaseJwtRealm();
|
||||
if (authCacheProperties.isPermissionCachingEnabled()) {
|
||||
//设置权限缓存
|
||||
realm.setCachingEnabled(true);
|
||||
CacheManager cacheManager = V.notEmpty(redisCacheManager())? redisCacheManager(): memoryCacheManager();
|
||||
realm.setCacheManager(cacheManager);
|
||||
}
|
||||
return realm;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ import java.util.List;
|
|||
* @date 2019/6/20
|
||||
*/
|
||||
@RestController
|
||||
@AuthorizationPrefix(prefix = "permission", code = "permission", name = "权限")
|
||||
@RequestMapping("/permission")
|
||||
@AuthorizationPrefix(prefix = "permission", code = "permission", name = "权限管理")
|
||||
public class PermissionController extends BaseCrudRestController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PermissionService.class);
|
||||
|
@ -46,7 +46,7 @@ public class PermissionController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("get"), name = "查看")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("read"), name = "读取")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
PermissionVO vo = permissionService.getViewObject(id, PermissionVO.class);
|
||||
|
@ -76,8 +76,8 @@ public class PermissionController extends BaseCrudRestController {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("permission:add")
|
||||
@PostMapping("/")
|
||||
// @AuthorizationWrapper(value = @RequiresPermissions("create"), name = "新建")
|
||||
public JsonResult createEntity(@ModelAttribute PermissionVO viewObject, BindingResult result, HttpServletRequest request)
|
||||
throws Exception{
|
||||
// 转换
|
||||
|
@ -92,8 +92,8 @@ public class PermissionController extends BaseCrudRestController {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("permission:update")
|
||||
@PutMapping("/{id}")
|
||||
// @AuthorizationWrapper(value = @RequiresPermissions("update"), name = "更新")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Permission entity, BindingResult result,
|
||||
HttpServletRequest request) throws Exception{
|
||||
return super.updateEntity(entity, result);
|
||||
|
@ -105,8 +105,8 @@ public class PermissionController extends BaseCrudRestController {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequiresPermissions("permission:delete")
|
||||
@DeleteMapping("/{id}")
|
||||
// @AuthorizationWrapper(value = @RequiresPermissions("delete"), name = "删除")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,14 @@ import com.diboot.core.vo.JsonResult;
|
|||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationCache;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationPrefix;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.entity.Role;
|
||||
import com.diboot.shiro.service.RoleService;
|
||||
import com.diboot.shiro.vo.RoleVO;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
@ -24,6 +28,7 @@ import java.util.List;
|
|||
|
||||
@RestController
|
||||
@RequestMapping("/role")
|
||||
@AuthorizationPrefix(prefix = "role", code = "role", name = "角色管理")
|
||||
public class RoleController extends BaseCrudRestController {
|
||||
|
||||
@Autowired
|
||||
|
@ -43,33 +48,25 @@ public class RoleController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResult getVOList(Role role, Pagination pagination, HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Role> queryWrapper = super.buildQueryWrapper(role);
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("list"), name = "列表")
|
||||
@AuthorizationCache
|
||||
public JsonResult getVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Role> queryWrapper = buildQuery(request);
|
||||
// 构建分页
|
||||
Pagination pagination = buildPagination(request);
|
||||
// 获取结果
|
||||
List<RoleVO> voList = roleService.getRoleList(queryWrapper, pagination);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, voList).bindPagination(pagination);
|
||||
}
|
||||
|
||||
/***
|
||||
* 显示创建页面
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/toCreatePage")
|
||||
public JsonResult toCreatePage(HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
List<Permission> menuList = roleService.getAllMenu();
|
||||
modelMap.put("menuList", menuList);
|
||||
return new JsonResult(modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("create"), name = "新建")
|
||||
public JsonResult createEntity(@RequestBody Role entity, BindingResult result, HttpServletRequest request)
|
||||
throws Exception{
|
||||
// 创建
|
||||
|
@ -81,19 +78,6 @@ public class RoleController extends BaseCrudRestController {
|
|||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 显示更新页面
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/toUpdatePage/{id}")
|
||||
public JsonResult toUpdatePage(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
RoleVO roleVO = roleService.toUpdatePage(id);
|
||||
return new JsonResult(roleVO);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id ID
|
||||
|
@ -101,6 +85,7 @@ public class RoleController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("update"), name = "更新")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @RequestBody Role entity, BindingResult result,
|
||||
HttpServletRequest request) throws Exception{
|
||||
// Model属性值验证结果
|
||||
|
@ -125,6 +110,7 @@ public class RoleController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("read"), name = "读取")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
RoleVO roleVO = roleService.getRole(id);
|
||||
|
@ -138,6 +124,7 @@ public class RoleController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("delete"), name = "删除")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
boolean success = roleService.deleteRole(id);
|
||||
if(success){
|
||||
|
@ -147,6 +134,34 @@ public class RoleController extends BaseCrudRestController {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 显示创建页面
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/toCreatePage")
|
||||
public JsonResult toCreatePage(HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
List<Permission> menuList = roleService.getAllMenu();
|
||||
modelMap.put("menuList", menuList);
|
||||
return new JsonResult(modelMap);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 显示更新页面
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/toUpdatePage/{id}")
|
||||
public JsonResult toUpdatePage(@PathVariable("id")Long id, HttpServletRequest request)
|
||||
throws Exception{
|
||||
RoleVO roleVO = roleService.toUpdatePage(id);
|
||||
return new JsonResult(roleVO);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 获取所有菜单,以及每个菜单下的所有权限
|
||||
* @return
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.diboot.shiro.entity;
|
|||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.util.V;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -34,4 +35,11 @@ public class Role extends BaseEntity {
|
|||
@TableField(exist = false)
|
||||
private List<Permission> permissionList;
|
||||
|
||||
/***
|
||||
* 是否是管理员权限
|
||||
* @return
|
||||
*/
|
||||
public boolean isAdmin(){
|
||||
return V.equals(code, "ADMIN");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,12 +13,14 @@ import org.apache.shiro.authc.AuthenticationToken;
|
|||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
import org.apache.shiro.realm.AuthorizingRealm;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ public class ProxyToTargetObjectHelper {
|
|||
|
||||
/**
|
||||
* 获取代理对象的目标对象
|
||||
* 对象可能被多次代理,所以需要递归获取原始对象
|
||||
* @param proxy
|
||||
* @return
|
||||
* @throws Exception
|
||||
|
@ -27,12 +28,13 @@ public class ProxyToTargetObjectHelper {
|
|||
}
|
||||
//判断是jdk动态代理还是cglib代理
|
||||
if(AopUtils.isJdkDynamicProxy(proxy)) {
|
||||
return getJdkDynamicProxyTargetObject(proxy);
|
||||
proxy = getJdkDynamicProxyTargetObject(proxy);
|
||||
}
|
||||
//cglib
|
||||
else {
|
||||
return getCglibProxyTargetObject(proxy);
|
||||
proxy = getCglibProxyTargetObject(proxy);
|
||||
}
|
||||
return getTarget(proxy);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue