完成 服务启动之后权限自动入库
This commit is contained in:
parent
1d6ce88f35
commit
ade3e1fe5f
|
@ -0,0 +1,40 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
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("/authorization")
|
||||
@AuthorizationPrefix(name = "测试权限", code = "authorization", prefix = "authorization")
|
||||
public class AuthorizationWrapperController {
|
||||
|
||||
/**此处权限为:authorization:get 或 authorization:test*/
|
||||
@GetMapping("/get")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions(value = {"get", "test"},
|
||||
logical = Logical.OR),
|
||||
name = {"查看", "测试"})
|
||||
public JsonResult get() {
|
||||
return new JsonResult("ok");
|
||||
}
|
||||
|
||||
/**此处权限为:getAll 或 test*/
|
||||
@GetMapping("/getAll")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions({"getAll", "test"}),
|
||||
name = {"获取所有", "测试"},
|
||||
ignorePrefix = true)
|
||||
public JsonResult getAll() {
|
||||
return new JsonResult("ok");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.diboot.example.listener;
|
||||
|
||||
import com.diboot.shiro.authz.storage.EnableStorageEnum;
|
||||
import com.diboot.shiro.listener.AbstractStorageApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 示例监听器
|
||||
* {@link AbstractStorageApplicationListener}丰富了 {@link org.springframework.context.ApplicationListener}
|
||||
* {@link AbstractStorageApplicationListener}中封装了将{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper}权限自动入库的操作
|
||||
* 当你使用注解{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper},建议直接继承{@link AbstractStorageApplicationListener}
|
||||
* 然后对{@link AbstractStorageApplicationListener#customExecute(ContextRefreshedEvent)}方法进行重写
|
||||
* 注:需要手动设置一个默认构造函数,传递是否自动权限入库
|
||||
* @author : wee
|
||||
* @version : v 2.0
|
||||
* @Date 2019-06-18 23:11
|
||||
*/
|
||||
@Component
|
||||
public class ExampleListener extends AbstractStorageApplicationListener {
|
||||
|
||||
/**需要手动实现构造来设置是否开启权限入库操作,默认入库*/
|
||||
protected ExampleListener() {
|
||||
super(EnableStorageEnum.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统启动后,客户自定义事件
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
protected void customExecute(ContextRefreshedEvent event) {
|
||||
System.out.println("============00000000");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.diboot.shiro.authz.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 权限注解的前缀,用于controller注解<br/>
|
||||
* <strong>注:当你使用{@link AuthorizationWrapper},请在类上使用{@link AuthorizationPrefix}注解进行标记,系统启动的时候才会将权限入库</strong>
|
||||
* @author : wee
|
||||
* @version v 2.0
|
||||
* @Date 2019-06-17 20:42
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface AuthorizationPrefix {
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*
|
||||
* 设置当前权限前缀名称
|
||||
* @return
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*
|
||||
* 设置当前权限前缀编码
|
||||
* @return
|
||||
*/
|
||||
String code();
|
||||
|
||||
/**
|
||||
* <h3>{@link AuthorizationWrapper#requiresPermissions()#value()}的前缀</h3>
|
||||
* <ul>
|
||||
* <li> value = permissions</li>
|
||||
* <li>{@link AuthorizationWrapper#requiresPermissions()#value()} = {"list", "get"}</li>
|
||||
* <li>实际权限为:{"permissions:list", "permissions:list"}</li>
|
||||
* </ul>
|
||||
* 注:当前注解优先级低于{@link AuthorizationWrapper#prefix()},
|
||||
* 如果两者都配置优先使用{@link AuthorizationWrapper#prefix()}
|
||||
* @return
|
||||
*/
|
||||
String prefix() default "";
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.diboot.shiro.authz.annotation;
|
||||
|
||||
import org.apache.shiro.authz.annotation.*;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 权限包装:目前只包装{@link RequiresPermissions},可以根据需要包装{@link RequiresRoles}
|
||||
* @author : wee
|
||||
* @version v 1.0
|
||||
* @Date 2019-06-19 00:40
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface AuthorizationWrapper {
|
||||
|
||||
/**RequiresPermissions包装*/
|
||||
RequiresPermissions value();
|
||||
|
||||
/**权限别名:用于存储到数据库,与{@link RequiresPermissions#value()}的值一一对应*/
|
||||
String[] name();
|
||||
|
||||
/**设置前缀:用于拼接,详细描述参考{@link AuthorizationPrefix#prefix()}*/
|
||||
String prefix() default "";
|
||||
|
||||
/**是否忽略前缀:默认不忽略*/
|
||||
boolean ignorePrefix() default false;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.diboot.shiro.authz.aop;
|
||||
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import com.diboot.shiro.authz.handler.AuthorizationWrapperAnnotationHandler;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.aop.MethodInvocation;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
|
||||
|
||||
/**
|
||||
* {@link AuthorizationWrapper} 拦截器
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-14 22:19
|
||||
*/
|
||||
public class AuthorizationWrapperAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
|
||||
/**
|
||||
* Default no-argument constructor that ensures this interceptor looks for
|
||||
* {@link AuthorizationWrapper AuthorizationWrapper} annotations in a method declaration.
|
||||
*/
|
||||
public AuthorizationWrapperAnnotationMethodInterceptor() {
|
||||
super( new AuthorizationWrapperAnnotationHandler() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resolver
|
||||
* @since 1.1
|
||||
*/
|
||||
public AuthorizationWrapperAnnotationMethodInterceptor(AnnotationResolver resolver) {
|
||||
super( new AuthorizationWrapperAnnotationHandler(), resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当使用AuthorizationWrapper注解进行权限验证的时候,自动的去追加前缀
|
||||
* @param mi
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
@Override
|
||||
public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
|
||||
try {
|
||||
((AuthorizationWrapperAnnotationHandler)getHandler()).assertAuthorized(getResolver(), mi);
|
||||
}
|
||||
catch(AuthorizationException ae) {
|
||||
if (ae.getCause() == null) {
|
||||
ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
|
||||
}
|
||||
throw ae;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.diboot.shiro.bind.aop;
|
||||
package com.diboot.shiro.authz.aop;
|
||||
|
||||
import com.diboot.shiro.bind.aop.PermissionWrapperAnnotationMethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
|
@ -12,6 +11,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义AOP拦截
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-15 12:07
|
||||
|
@ -21,7 +21,7 @@ public class CustomAopAllianceAnnotationsAuthorizingMethodInterceptor extends An
|
|||
List<AuthorizingAnnotationMethodInterceptor> interceptors =
|
||||
new ArrayList<AuthorizingAnnotationMethodInterceptor>(6);
|
||||
AnnotationResolver resolver = new SpringAnnotationResolver();
|
||||
interceptors.add(new PermissionWrapperAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new AuthorizationWrapperAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
|
||||
interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
|
|
@ -1,6 +1,6 @@
|
|||
package com.diboot.shiro.bind.aop;
|
||||
package com.diboot.shiro.authz.aop;
|
||||
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsWrapper;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import org.apache.shiro.authz.annotation.*;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -12,6 +12,7 @@ import java.lang.annotation.Annotation;
|
|||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 自定义切片装配器
|
||||
* @author : wee
|
||||
* @version : v1.0
|
||||
* @Date 2019-06-15 12:27
|
||||
|
@ -22,7 +23,7 @@ public class CustomAuthorizationAttributeSourceAdvisor extends StaticMethodMatch
|
|||
|
||||
private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
|
||||
new Class[] {
|
||||
RequiresPermissionsWrapper.class,
|
||||
AuthorizationWrapper.class,
|
||||
RequiresPermissions.class, RequiresRoles.class,
|
||||
RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
|
||||
};
|
||||
|
@ -48,7 +49,7 @@ public class CustomAuthorizationAttributeSourceAdvisor extends StaticMethodMatch
|
|||
* Returns <tt>true</tt> if the method or the class has any Shiro annotations, false otherwise.
|
||||
* The annotations inspected are:
|
||||
* <ul>
|
||||
* <li>{@link RequiresPermissionsWrapper RequiresPermissionsWrapper}</li>
|
||||
* <li>{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper AuthorizationWrapper}</li>
|
||||
* <li>{@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}</li>
|
||||
* <li>{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}</li>
|
||||
* <li>{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}</li>
|
|
@ -0,0 +1,112 @@
|
|||
package com.diboot.shiro.authz.handler;
|
||||
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationPrefix;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.aop.MethodInvocation;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
|
||||
import org.apache.shiro.authz.aop.PermissionAnnotationHandler;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* {@link AuthorizationWrapper} 助手类, 参考{@link PermissionAnnotationHandler}实现
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-14 22:19
|
||||
*/
|
||||
public class AuthorizationWrapperAnnotationHandler extends AuthorizingAnnotationHandler {
|
||||
|
||||
/**
|
||||
* 标记服务的注解
|
||||
*/
|
||||
public AuthorizationWrapperAnnotationHandler() {
|
||||
super(AuthorizationWrapper.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回{@link AuthorizationWrapper#value()#value} value}
|
||||
* @param a ${@link AuthorizationWrapper}
|
||||
* @return
|
||||
*/
|
||||
protected String[] getAnnotationValue(Annotation a) {
|
||||
AuthorizationWrapper rpAnnotation = (AuthorizationWrapper) a;
|
||||
return rpAnnotation.value().value();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验注解{@link AuthorizationWrapper},自定义包装类,
|
||||
* 使用${@link AuthorizationWrapperAnnotationHandler#assertAuthorized(AnnotationResolver, MethodInvocation)}进行权限验证
|
||||
*/
|
||||
@Override
|
||||
public void assertAuthorized(Annotation a) throws AuthorizationException {}
|
||||
|
||||
/**
|
||||
* 校验注解{@link AuthorizationWrapper}
|
||||
*/
|
||||
public void assertAuthorized(AnnotationResolver resolver, MethodInvocation mi) throws AuthorizationException {
|
||||
//如果方法上存在AuthorizationWrapper注解,那么resolver.getAnnotation()获取的是AuthorizationWrapper注解,会优先从缓存读取
|
||||
AuthorizationWrapper authorizationWrapper = (AuthorizationWrapper)resolver.getAnnotation(mi, AuthorizationWrapper.class);
|
||||
String[] perms = getAnnotationValue(authorizationWrapper);
|
||||
Subject subject = getSubject();
|
||||
//如果忽略前缀,那么则不拼接前缀
|
||||
perms = addPrefix(resolver, mi, authorizationWrapper, perms);
|
||||
if (perms.length == 1) {
|
||||
subject.checkPermission(perms[0]);
|
||||
return;
|
||||
}
|
||||
if (Logical.AND.equals(authorizationWrapper.value().logical())) {
|
||||
getSubject().checkPermissions(perms);
|
||||
return;
|
||||
}
|
||||
if (Logical.OR.equals(authorizationWrapper.value().logical())) {
|
||||
boolean hasAtLeastOnePermission = false;
|
||||
for (String permission : perms) {
|
||||
if (getSubject().isPermitted(permission)) {
|
||||
hasAtLeastOnePermission = true;
|
||||
}
|
||||
}
|
||||
if (!hasAtLeastOnePermission) {
|
||||
getSubject().checkPermission(perms[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向 perms 追加前缀
|
||||
* @param resolver
|
||||
* @param mi
|
||||
* @param authorizationWrapper
|
||||
* @param perms
|
||||
* @return
|
||||
*/
|
||||
private String[] addPrefix(AnnotationResolver resolver, MethodInvocation mi, AuthorizationWrapper authorizationWrapper, String[] perms) {
|
||||
if (!authorizationWrapper.ignorePrefix()) {
|
||||
String prefix = "";
|
||||
if (V.notEmpty(authorizationWrapper.prefix())) {
|
||||
prefix = authorizationWrapper.prefix();
|
||||
} else {
|
||||
//如果自身不定义,查找前缀注解,存在则设置值
|
||||
AuthorizationPrefix authorizationPrefix = (AuthorizationPrefix)resolver.getAnnotation(mi, AuthorizationPrefix.class);
|
||||
if (V.notEmpty(authorizationPrefix)) {
|
||||
prefix = authorizationPrefix.prefix();
|
||||
}
|
||||
}
|
||||
String [] permsTemp = new String[perms.length];
|
||||
//前缀存在的时候,才做组装,其他情况不处理
|
||||
if (V.notEmpty(prefix)) {
|
||||
for (int i = 0; i < perms.length; i++) {
|
||||
permsTemp[i] = S.join(prefix, ":", perms[i]);
|
||||
}
|
||||
perms = permsTemp;
|
||||
}
|
||||
}
|
||||
return perms;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.diboot.shiro.authz.storage;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 是否开启存储枚举
|
||||
* @author : wee
|
||||
* @version : v 1.0
|
||||
* @Date 2019-06-18 23:06
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum EnableStorageEnum {
|
||||
TRUE(true),
|
||||
FALSE(false);
|
||||
private boolean storagePermissions;
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.diboot.shiro.authz.storage;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Yangzhao
|
||||
* @version v2.0
|
||||
* @date 2019/6/6
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class PermissionStorage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 147840093814049689L;
|
||||
|
||||
/***
|
||||
* 默认逻辑删除标记,deleted=0有效
|
||||
*/
|
||||
private boolean deleted = false;
|
||||
|
||||
/**菜单Id*/
|
||||
private Long menuId;
|
||||
|
||||
/**菜单编码*/
|
||||
private String menuCode;
|
||||
|
||||
/**菜单名称*/
|
||||
private String menuName;
|
||||
|
||||
/**权限编码*/
|
||||
private String permissionCode;
|
||||
|
||||
/**权限名称*/
|
||||
private String permissionName;
|
||||
|
||||
/**是否高优先级:方法上的优先级高于类上,同时出现以方法为准*/
|
||||
private boolean highPriority;
|
||||
|
||||
private Long id;
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package com.diboot.shiro.bind.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 权限注解的前缀,用于controller注解
|
||||
*
|
||||
* @author : wee
|
||||
* @version v 2.0
|
||||
* @Date 2019-06-17 20:42
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface PermissionsPrefix {
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*
|
||||
* 设置当前权限前缀名称
|
||||
* @return
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*
|
||||
* 设置当前权限前缀编码
|
||||
* @return
|
||||
*/
|
||||
String code();
|
||||
|
||||
/**
|
||||
* <h3>{@link RequiresPermissionsWrapper#value()}的前缀</h3>
|
||||
* <ul>
|
||||
* <li> value = permissions</li>
|
||||
* <li>{@link RequiresPermissionsWrapper#value()} = {"list", "get"}</li>
|
||||
* <li>实际权限为:{"permissions:list", "permissions:list"}</li>
|
||||
* </ul>
|
||||
* 注:当前注解优先级低于{@link RequiresPermissionsWrapper#prefix()},
|
||||
* 如果两者都配置优先使用{@link RequiresPermissionsWrapper#prefix()}
|
||||
* @return
|
||||
*/
|
||||
String prefix() default "";
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package com.diboot.shiro.bind.annotation;
|
||||
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 注解{@link RequiresPermissions}的包装,增加权限描述等字段
|
||||
* @author : wee
|
||||
* @version v2.0
|
||||
* @Date 2019-06-14 17:50
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface RequiresPermissionsWrapper {
|
||||
|
||||
/**
|
||||
* 包装 {@link RequiresPermissions#value()}
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* 包装 {@link RequiresPermissions#logical()}
|
||||
*/
|
||||
Logical logical() default Logical.AND;
|
||||
|
||||
/**
|
||||
* 权限名称
|
||||
* @return
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 参照{@link PermissionsPrefix#prefix()}解释
|
||||
* @return
|
||||
*/
|
||||
String prefix() default "";
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package com.diboot.shiro.bind.aop;
|
||||
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsWrapper;
|
||||
import com.diboot.shiro.bind.handler.PermissionWrapperAnnotationHandler;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.aop.MethodInvocation;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
|
||||
|
||||
/**
|
||||
* {@link RequiresPermissionsWrapper} 拦截器
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-14 22:19
|
||||
*/
|
||||
public class PermissionWrapperAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
|
||||
/**
|
||||
* Default no-argument constructor that ensures this interceptor looks for
|
||||
* {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotations in a method declaration.
|
||||
*/
|
||||
public PermissionWrapperAnnotationMethodInterceptor() {
|
||||
super( new PermissionWrapperAnnotationHandler() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resolver
|
||||
* @since 1.1
|
||||
*/
|
||||
public PermissionWrapperAnnotationMethodInterceptor(AnnotationResolver resolver) {
|
||||
super( new PermissionWrapperAnnotationHandler(), resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当使用RequiresPermissionsWrapper注解进行权限验证的时候,自动的去追加前缀
|
||||
* @param mi
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
@Override
|
||||
public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
|
||||
try {
|
||||
|
||||
//默认是直接调用方法上注解,现在修改成 获取类和方法上的注解
|
||||
// ((AuthorizingAnnotationHandler)getHandler()).assertAuthorized(getAnnotation(mi));
|
||||
((PermissionWrapperAnnotationHandler)getHandler()).assertAuthorized(getResolver(), mi);
|
||||
}
|
||||
catch(AuthorizationException ae) {
|
||||
if (ae.getCause() == null) {
|
||||
ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
|
||||
}
|
||||
throw ae;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
package com.diboot.shiro.bind.handler;
|
||||
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.bind.annotation.PermissionsPrefix;
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsWrapper;
|
||||
import org.apache.shiro.aop.AnnotationResolver;
|
||||
import org.apache.shiro.aop.MethodInvocation;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
|
||||
import org.apache.shiro.authz.aop.PermissionAnnotationHandler;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link RequiresPermissionsWrapper} 助手类, 参考{@link PermissionAnnotationHandler}实现
|
||||
* @author : wee
|
||||
* @version : v2.0
|
||||
* @Date 2019-06-14 22:19
|
||||
*/
|
||||
public class PermissionWrapperAnnotationHandler extends AuthorizingAnnotationHandler {
|
||||
|
||||
private final static String REQUIRES_PERMISSIONS_VALUE = "value";
|
||||
|
||||
private final static String REQUIRES_PERMISSIONS_LOGICAL = "logical";
|
||||
|
||||
private final static String JDK_MEMBER_VALUES = "memberValues";
|
||||
|
||||
/**
|
||||
* 标记服务的注解
|
||||
*/
|
||||
public PermissionWrapperAnnotationHandler() {
|
||||
super(RequiresPermissionsWrapper.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the annotation {@link RequiresPermissions#value value}, from which the Permission will be constructed.
|
||||
*
|
||||
* @param a the RequiresPermissions annotation being inspected.
|
||||
* @return the annotation's <code>value</code>, from which the Permission will be constructed.
|
||||
*/
|
||||
protected String[] getAnnotationValue(Annotation a) {
|
||||
RequiresPermissionsWrapper rpAnnotation = (RequiresPermissionsWrapper) a;
|
||||
return rpAnnotation.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验注解{@link RequiresPermissionsWrapper}
|
||||
*/
|
||||
@Override
|
||||
public void assertAuthorized(Annotation a) throws AuthorizationException {
|
||||
if (!(a instanceof RequiresPermissionsWrapper)) {
|
||||
return;
|
||||
}
|
||||
RequiresPermissionsWrapper rppAnnotation = (RequiresPermissionsWrapper) a;
|
||||
String[] perms = getAnnotationValue(a);
|
||||
Subject subject = getSubject();
|
||||
|
||||
if (perms.length == 1) {
|
||||
subject.checkPermission(perms[0]);
|
||||
return;
|
||||
}
|
||||
if (Logical.AND.equals(rppAnnotation.logical())) {
|
||||
getSubject().checkPermissions(perms);
|
||||
return;
|
||||
}
|
||||
if (Logical.OR.equals(rppAnnotation.logical())) {
|
||||
boolean hasAtLeastOnePermission = false;
|
||||
for (String permission : perms) {
|
||||
if (getSubject().isPermitted(permission)) {
|
||||
hasAtLeastOnePermission = true;
|
||||
}
|
||||
}
|
||||
if (!hasAtLeastOnePermission) {
|
||||
getSubject().checkPermission(perms[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验注解{@link RequiresPermissionsWrapper}
|
||||
*/
|
||||
public void assertAuthorized(AnnotationResolver resolver, MethodInvocation mi) throws AuthorizationException {
|
||||
//如果方法上存在RequiresPermissionsWrapper注解,那么resolver.getAnnotation()获取的是RequiresPermissionsWrapper注解
|
||||
//优先从缓存读取
|
||||
RequiresPermissionsWrapper requiresPermissionsWrapper = (RequiresPermissionsWrapper)resolver.getAnnotation(mi, RequiresPermissionsWrapper.class);
|
||||
String prefix = "";
|
||||
if (V.notEmpty(requiresPermissionsWrapper.prefix())) {
|
||||
prefix = requiresPermissionsWrapper.prefix();
|
||||
} else {
|
||||
//如果自身不定义,查找前缀注解,存在则设置值
|
||||
PermissionsPrefix permissionsPrefix = (PermissionsPrefix)resolver.getAnnotation(mi, PermissionsPrefix.class);
|
||||
if (V.notEmpty(permissionsPrefix)) {
|
||||
prefix = permissionsPrefix.prefix();
|
||||
}
|
||||
}
|
||||
|
||||
String[] perms = getAnnotationValue(requiresPermissionsWrapper);
|
||||
Subject subject = getSubject();
|
||||
|
||||
String [] permsTemp = new String[perms.length];
|
||||
//前缀存在的时候,才做组装,其他情况不处理
|
||||
if (V.notEmpty(prefix)) {
|
||||
for (int i = 0; i < perms.length; i++) {
|
||||
permsTemp[i] = S.join(prefix, ":", perms[i]);
|
||||
}
|
||||
perms = permsTemp;
|
||||
}
|
||||
|
||||
if (perms.length == 1) {
|
||||
subject.checkPermission(perms[0]);
|
||||
return;
|
||||
}
|
||||
if (Logical.AND.equals(requiresPermissionsWrapper.logical())) {
|
||||
getSubject().checkPermissions(perms);
|
||||
return;
|
||||
}
|
||||
if (Logical.OR.equals(requiresPermissionsWrapper.logical())) {
|
||||
boolean hasAtLeastOnePermission = false;
|
||||
for (String permission : perms) {
|
||||
if (getSubject().isPermitted(permission)) {
|
||||
hasAtLeastOnePermission = true;
|
||||
}
|
||||
}
|
||||
if (!hasAtLeastOnePermission) {
|
||||
getSubject().checkPermission(perms[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态修改注解的值(不可用)
|
||||
* @param rppAnnotation
|
||||
*/
|
||||
@Deprecated
|
||||
private void proxy(RequiresPermissionsWrapper rppAnnotation) {
|
||||
try {
|
||||
//获取RequiresPermissionsProxy上的RequiresPermissions注解
|
||||
RequiresPermissions requiresPermissions = rppAnnotation.annotationType().getAnnotation(RequiresPermissions.class);
|
||||
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(requiresPermissions);
|
||||
/* memberValues 为JDK中存储所有成员变量值的Map {@link AnnotationInvocationHandler#memberValues}*/
|
||||
Field jdkValue = invocationHandler.getClass().getDeclaredField(JDK_MEMBER_VALUES);
|
||||
jdkValue.setAccessible(true);
|
||||
/*获取RequiresPermissions对应的代理属性值*/
|
||||
Map<String, Object> memberValues = (Map<String, Object>) jdkValue.get(invocationHandler);
|
||||
/*动态设置RequiresPermissions注解的内容*/
|
||||
memberValues.put(REQUIRES_PERMISSIONS_VALUE, rppAnnotation.value());
|
||||
memberValues.put(REQUIRES_PERMISSIONS_LOGICAL, rppAnnotation.logical());
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.diboot.shiro.config;
|
||||
|
||||
import com.diboot.shiro.bind.aop.CustomAuthorizationAttributeSourceAdvisor;
|
||||
import com.diboot.shiro.authz.aop.CustomAuthorizationAttributeSourceAdvisor;
|
||||
import com.diboot.shiro.jwt.BaseJwtAuthenticationFilter;
|
||||
import com.diboot.shiro.jwt.BaseJwtRealm;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
|
|
|
@ -7,8 +7,8 @@ import com.diboot.core.util.BeanUtils;
|
|||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.shiro.bind.annotation.PermissionsPrefix;
|
||||
import com.diboot.shiro.bind.annotation.RequiresPermissionsWrapper;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationPrefix;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.service.PermissionService;
|
||||
import com.diboot.shiro.vo.PermissionVO;
|
||||
|
@ -30,7 +30,7 @@ import java.util.List;
|
|||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@RestController
|
||||
@PermissionsPrefix(prefix = "permission", code = "permission", name = "权限")
|
||||
@AuthorizationPrefix(prefix = "permission", code = "permission", name = "权限")
|
||||
@RequestMapping("/permission")
|
||||
public class PermissionController extends BaseCrudRestController {
|
||||
|
||||
|
@ -46,7 +46,7 @@ public class PermissionController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@RequiresPermissionsWrapper(prefix = "permissionSelf", value = {"get"}, name = "查看")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("get"), name = "查看")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
PermissionVO vo = permissionService.getViewObject(id, PermissionVO.class);
|
||||
|
@ -62,7 +62,7 @@ public class PermissionController extends BaseCrudRestController {
|
|||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@RequiresPermissionsWrapper(value = {"list"}, name = "列表")
|
||||
@AuthorizationWrapper(value = @RequiresPermissions("list"), name = "列表")
|
||||
public JsonResult getVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Permission> queryWrapper = buildQuery(request);
|
||||
// 构建分页
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.diboot.shiro.entity;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -14,6 +16,9 @@ public class Permission extends BaseEntity {
|
|||
|
||||
private static final long serialVersionUID = 7713768302925692987L;
|
||||
|
||||
@TableField
|
||||
private Long menuId;
|
||||
|
||||
@TableField
|
||||
private String menuCode;
|
||||
|
||||
|
@ -26,4 +31,8 @@ public class Permission extends BaseEntity {
|
|||
@TableField
|
||||
private String permissionName;
|
||||
|
||||
/**此处覆盖了父类的属性,初始化权限的时候需要设置该值,父类默认不设置*/
|
||||
// @TableField
|
||||
// private boolean deleted = false;
|
||||
|
||||
}
|
||||
|
|
|
@ -21,30 +21,30 @@ public class BaseJwtAuthenticationToken implements AuthenticationToken {
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseJwtAuthenticationToken.class);
|
||||
|
||||
// 登录用的账号(此处的这个账号是一种抽象的概念)
|
||||
/**登录用的账号(此处的这个账号是一种抽象的概念*/
|
||||
private String account;
|
||||
|
||||
// 登录用的密码 (此处的这个密码也是一种抽象的概念)
|
||||
/**登录用的密码 (此处的这个密码也是一种抽象的概念*/
|
||||
private String password;
|
||||
|
||||
// 登录使用方式
|
||||
/**登录使用方式*/
|
||||
private AuthType authType;
|
||||
|
||||
// auth token
|
||||
/**authz token*/
|
||||
private String authtoken;
|
||||
|
||||
// 申请token的密码
|
||||
/**申请token的密码*/
|
||||
private String applyTokenSecret;
|
||||
|
||||
// 签名key (默认SIGN_KEY,配置signKey, 或微信state, 密码等)
|
||||
/**签名key (默认SIGN_KEY,配置signKey, 或微信state, 密码等)*/
|
||||
private String signKey = JwtHelper.SIGN_KEY;
|
||||
|
||||
// 过期时间
|
||||
/**过期时间*/
|
||||
private long expiresInMinutes = JwtHelper.EXPIRES_IN_MINUTES;
|
||||
|
||||
private Map<String, AuthWayService> authWayServiceMap;
|
||||
|
||||
// 默认构造函数
|
||||
/**默认构造函数*/
|
||||
public BaseJwtAuthenticationToken(){
|
||||
|
||||
}
|
||||
|
|
|
@ -31,11 +31,12 @@ public class BaseJwtRealm extends AuthorizingRealm {
|
|||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
@Override
|
||||
public boolean supports(AuthenticationToken token) {
|
||||
return token != null && token instanceof BaseJwtAuthenticationToken;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<?> getAuthenticationTokenClass() {
|
||||
return BaseJwtRealm.class;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
package com.diboot.shiro.listener;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationPrefix;
|
||||
import com.diboot.shiro.authz.annotation.AuthorizationWrapper;
|
||||
import com.diboot.shiro.authz.storage.EnableStorageEnum;
|
||||
import com.diboot.shiro.authz.storage.PermissionStorage;
|
||||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.service.impl.PermissionServiceImpl;
|
||||
import com.diboot.shiro.util.ProxyToTargetObjectHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* {@link AbstractStorageApplicationListener}实现{@link ApplicationListener}接口,
|
||||
* <br/>
|
||||
* 并重新对外提供抽象{@link AbstractStorageApplicationListener#customExecute},功能等同于{@link ApplicationListener#onApplicationEvent};
|
||||
* <br/>
|
||||
* {@link AbstractStorageApplicationListener}中封装了将{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper}权限自动入库的操作,
|
||||
* <strong>注:权限入库每个Controller需要加上类注解{@link AuthorizationPrefix}用于识别</strong>
|
||||
* <br/>
|
||||
* 当你使用注解{@link com.diboot.shiro.authz.annotation.AuthorizationWrapper},建议直接继承{@link AbstractStorageApplicationListener},
|
||||
* <br/>
|
||||
* 且你的实现类需要手动设置一个默认构造函数来设置{@link AbstractStorageApplicationListener#storagePermissions},传递是否自动权限入库
|
||||
*
|
||||
* @author : wee
|
||||
* @version : v 2.0
|
||||
* @Date 2019-06-18 23:12
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class AbstractStorageApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
/**存储数据库中已经存在的permissionCode和ID的关系,主要用于更新数据*/
|
||||
private static Map<String, Permission> dbPermissionMap = new HashMap<>();
|
||||
|
||||
/**代码中的所有权限数据 key: {@link PermissionStorage#getPermissionCode()} value: {@link Permission}*/
|
||||
private static Map<String, PermissionStorage> loadCodePermissionMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static List<Permission> updateOrCreateOrDeletePermissionList = new ArrayList<>();
|
||||
/**
|
||||
* 默认开启存储
|
||||
*/
|
||||
protected boolean storagePermissions;
|
||||
|
||||
protected AbstractStorageApplicationListener(EnableStorageEnum enableStorageEnum) {
|
||||
this.storagePermissions = enableStorageEnum.isStoragePermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an application event.
|
||||
*
|
||||
* @param event the event to respond to
|
||||
*/
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
//防止重复执行
|
||||
if (V.isEmpty(event.getApplicationContext().getParent())) {
|
||||
/*自定义处理内容*/
|
||||
customExecute(event);
|
||||
/*判断客户是否开启存储权限,如果开启那么执行存储权限*/
|
||||
if (storagePermissions) {
|
||||
storagePermissions(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统启动后,客户自定义事件
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
protected abstract void customExecute(ContextRefreshedEvent event);
|
||||
|
||||
/**
|
||||
* 执行完自动权限后,自动赋值
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
private void storagePermissions(ContextRefreshedEvent event) {
|
||||
try {
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
|
||||
if (V.notEmpty(applicationContext)) {
|
||||
PermissionServiceImpl permissionService = applicationContext.getBean(PermissionServiceImpl.class);
|
||||
|
||||
//获取当前数据库中的有效的所有权限
|
||||
LambdaQueryWrapper<Permission> permissionLambdaQueryWrapper = Wrappers.lambdaQuery();
|
||||
permissionLambdaQueryWrapper.eq(Permission::isDeleted, false);
|
||||
List<Permission> permissionList = permissionService.getEntityList(permissionLambdaQueryWrapper);
|
||||
//存储数据库值
|
||||
for (Permission permission : permissionList) {
|
||||
dbPermissionMap.put(permission.getPermissionCode(), permission);
|
||||
}
|
||||
|
||||
//初始化数据:获取所有注解为AuthPrefix的代理bean<bean名称,bean的代理对象>
|
||||
Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(AuthorizationPrefix.class);
|
||||
if (V.isEmpty(beansWithAnnotation)) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) {
|
||||
//获取代理对象的目标对象(代理对象无法获取类上注解,所以需要转化成目标对象)
|
||||
Object target = ProxyToTargetObjectHelper.getTarget(entry.getValue());
|
||||
Class<?> targetClass = target.getClass();
|
||||
//获取类注解上的相关描述
|
||||
AuthorizationPrefix authorizationPrefix = targetClass.getAnnotation(AuthorizationPrefix.class);
|
||||
//判断Controller类上是否包含认证注解的包装
|
||||
if (targetClass.isAnnotationPresent(AuthorizationWrapper.class)) {
|
||||
buildPermissionStorageToMap(authorizationPrefix, targetClass.getAnnotation(AuthorizationWrapper.class), false);
|
||||
}
|
||||
//获取类中所有方法
|
||||
Method[] methods = target.getClass().getMethods();
|
||||
for (Method method : methods) {
|
||||
//取出含有注解的方法
|
||||
if (method.isAnnotationPresent(AuthorizationWrapper.class)) {
|
||||
buildPermissionStorageToMap(authorizationPrefix, method.getAnnotation(AuthorizationWrapper.class), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//保存、更新、删除 权限
|
||||
saveOrUpdateOrDeletePermission(permissionService);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("【初始化权限】<== 异常:", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建待存储的权限到map中
|
||||
* @param authorizationPrefix {@link AuthorizationPrefix}
|
||||
* @param authorizationWrapper {@link AuthorizationWrapper}
|
||||
*/
|
||||
private void buildPermissionStorageToMap(AuthorizationPrefix authorizationPrefix, AuthorizationWrapper authorizationWrapper, boolean highPriority) {
|
||||
String menuCode = authorizationPrefix.code();
|
||||
String menuName = authorizationPrefix.name();
|
||||
//如果不忽略前缀, 那么进行前缀补充 (如果允许,优先使用 AuthorizationWrapper注解的前缀)
|
||||
String prefix = "";
|
||||
if (!authorizationWrapper.ignorePrefix()) {
|
||||
prefix = V.notEmpty(authorizationWrapper.prefix()) ? authorizationWrapper.prefix() : authorizationPrefix.prefix();
|
||||
}
|
||||
//获取权限
|
||||
RequiresPermissions requiresPermissions = authorizationWrapper.value();
|
||||
//获取所有描述的权限code和name
|
||||
String[] value = requiresPermissions.value();
|
||||
String[] name = authorizationWrapper.name();
|
||||
//设置单个权限code和name
|
||||
String permissionName = "";
|
||||
String permissionCode = "";
|
||||
PermissionStorage permissionStorage;
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
//如果权限名称和值无法一一对应,那么当前权限组的所有数据的名称全部设置为最后一个name值
|
||||
permissionName = value.length != name.length ? name[name.length - 1] : name[i];
|
||||
//拼接权限值
|
||||
permissionCode = V.notEmpty(prefix) ? S.join(prefix, ":", value[i]) : value[i];
|
||||
PermissionStorage existPermission = loadCodePermissionMap.get(permissionCode);
|
||||
//如果不存在权限构建;当前存在的权限不是是高优先级的时候替换
|
||||
if (V.isEmpty(existPermission) || !existPermission.isHighPriority()) {
|
||||
//组装需要存储的权限
|
||||
permissionStorage = PermissionStorage.builder()
|
||||
.menuId(3L).menuCode(menuCode).menuName(menuName)
|
||||
.permissionCode(permissionCode).permissionName(permissionName)
|
||||
.deleted(false).highPriority(highPriority).build();
|
||||
//设置缓存
|
||||
loadCodePermissionMap.put(permissionCode, permissionStorage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <h3>保存、更新、删除 权限</h3>
|
||||
* <p>
|
||||
* 操作原则 以数据库字段为基准 匹配数据库中的权限和代码中的权限:<br>
|
||||
* * 如果代码中和数据库中相同,更新数据库中数据;<br>
|
||||
* * 如果代码中不存在,删除数据库中数据;<br>
|
||||
* </p>
|
||||
* @param permissionService
|
||||
*/
|
||||
private void saveOrUpdateOrDeletePermission(PermissionServiceImpl permissionService) {
|
||||
//记录修改和删除的权限数量
|
||||
int modifyCount = 0, removeCount = 0, totalCount = 0;
|
||||
List<Permission> saveOrUpdateOrDeletePermissionList = new ArrayList<>();
|
||||
//设置删除 or 修改
|
||||
for (Map.Entry<String, Permission> entry : dbPermissionMap.entrySet()) {
|
||||
PermissionStorage permissionStorage = loadCodePermissionMap.get(entry.getKey());
|
||||
Permission permission = entry.getValue();
|
||||
//存在则更新(设置ID)
|
||||
if (V.notEmpty(permissionStorage)) {
|
||||
if (isNeedModify(permission, permissionStorage)) {
|
||||
modifyCount++;
|
||||
permissionStorage.setId(permission.getId());
|
||||
//重置
|
||||
loadCodePermissionMap.put(entry.getKey(), permissionStorage);
|
||||
} else {
|
||||
//数据库中不需要修改的,在加载的数据中删除
|
||||
loadCodePermissionMap.remove(entry.getKey());
|
||||
}
|
||||
} else {
|
||||
//不存在: 表示需要删除
|
||||
removeCount++;
|
||||
permission.setDeleted(true);
|
||||
saveOrUpdateOrDeletePermissionList.add(permission);
|
||||
}
|
||||
|
||||
}
|
||||
//需要操作的数据=》转化为List<Permission>
|
||||
List<Permission> saveOrUpdatePermissionList;
|
||||
if (V.notEmpty(loadCodePermissionMap)) {
|
||||
totalCount = loadCodePermissionMap.values().size();
|
||||
List<PermissionStorage> permissionStorageList = loadCodePermissionMap.values().stream().collect(Collectors.toList());
|
||||
saveOrUpdatePermissionList = BeanUtils.convertList(permissionStorageList, Permission.class);
|
||||
saveOrUpdateOrDeletePermissionList.addAll(saveOrUpdatePermissionList);
|
||||
}
|
||||
//保存、更新、删除 权限
|
||||
boolean success = permissionService.saveOrUpdateBatch(saveOrUpdateOrDeletePermissionList);
|
||||
if (success) {
|
||||
log.debug("【初始化权限】<== 成功!共计权限{}个 新增【{}】个, 修改【{}】个,删除【{}】个!",
|
||||
totalCount, (saveOrUpdateOrDeletePermissionList.size() - modifyCount - removeCount), modifyCount, removeCount);
|
||||
} else {
|
||||
log.debug("【初始化权限】<== 失败!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个对象的属性是否相同,如果存在一处不同那么就需要修改
|
||||
* @param permission
|
||||
* @param permissionStorage
|
||||
* @return
|
||||
*/
|
||||
public boolean isNeedModify(Permission permission, PermissionStorage permissionStorage){
|
||||
if (!V.equals(permission.getMenuId(), permissionStorage.getMenuId())
|
||||
|| !V.equals(permission.getMenuCode(), permissionStorage.getMenuCode())
|
||||
|| !V.equals(permission.getMenuName(), permissionStorage.getMenuName())
|
||||
|| !V.equals(permission.getPermissionCode(), permissionStorage.getPermissionCode())
|
||||
|| !V.equals(permission.getPermissionName(), permissionStorage.getPermissionName())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,7 +4,6 @@ import com.diboot.core.service.impl.BaseServiceImpl;
|
|||
import com.diboot.shiro.entity.Permission;
|
||||
import com.diboot.shiro.mapper.PermissionMapper;
|
||||
import com.diboot.shiro.service.PermissionService;
|
||||
import com.diboot.shiro.service.SysUserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ public class JwtHelper {
|
|||
private static final Logger logger = LoggerFactory.getLogger(JwtHelper.class);
|
||||
|
||||
private static final String ISSUER = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.issuer")) ? BaseConfig.getProperty("diboot.shiro.jwt.issuer") : "diboot.com";
|
||||
private static final String AUTH_HEADER = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.auth.header.key")) ? BaseConfig.getProperty("diboot.shiro.jwt.auth.header.key") : "authtoken";
|
||||
private static final String AUTH_HEADER = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.authz.header.key")) ? BaseConfig.getProperty("diboot.shiro.jwt.authz.header.key") : "authtoken";
|
||||
private static final String TOKEN_PREFIX = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.token.prefix")) ? BaseConfig.getProperty("diboot.shiro.jwt.token.prefix") : "Bearer ";
|
||||
public static final String SIGN_KEY = V.notEmpty(BaseConfig.getProperty("diboot.shiro.jwt.signkey"))? BaseConfig.getProperty("diboot.shiro.jwt.signkey") : "Dibo2016Mazc";
|
||||
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package com.diboot.shiro.util;
|
||||
|
||||
import org.springframework.aop.framework.AdvisedSupport;
|
||||
import org.springframework.aop.framework.AopProxy;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 代理对象转成目标对象
|
||||
* @author : wee
|
||||
* @version : v 2.0
|
||||
* @Date 2019-06-19 14:42
|
||||
*/
|
||||
public class ProxyToTargetObjectHelper {
|
||||
|
||||
/**
|
||||
* 获取代理对象的目标对象
|
||||
* @param proxy
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Object getTarget(Object proxy) throws Exception {
|
||||
/*判断是否是代理对象*/
|
||||
if(!AopUtils.isAopProxy(proxy)) {
|
||||
return proxy;
|
||||
}
|
||||
//判断是jdk动态代理还是cglib代理
|
||||
if(AopUtils.isJdkDynamicProxy(proxy)) {
|
||||
return getJdkDynamicProxyTargetObject(proxy);
|
||||
}
|
||||
//cglib
|
||||
else {
|
||||
return getCglibProxyTargetObject(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取cglib代理的目标对象
|
||||
* @param proxy
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
|
||||
Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
|
||||
return getJdkOrCglibTargetObject(h, proxy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取jdk动态代理的目标对象
|
||||
* @param proxy
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
|
||||
Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
|
||||
return getJdkOrCglibTargetObject(h, proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据不用的代理获取目标对象
|
||||
* @param field
|
||||
* @param proxy
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Object getJdkOrCglibTargetObject(Field field, Object proxy) throws Exception{
|
||||
field.setAccessible(true);
|
||||
Object dynamic = field.get(proxy);
|
||||
Field advised;
|
||||
//如果是jdk代理
|
||||
if (dynamic instanceof AopProxy) {
|
||||
advised = ((AopProxy)dynamic).getClass().getDeclaredField("advised");
|
||||
}
|
||||
//如果是cglib代理
|
||||
advised = dynamic.getClass().getDeclaredField("advised");
|
||||
advised.setAccessible(true);
|
||||
//获取目标类
|
||||
return ((AdvisedSupport)advised.get(dynamic)).getTargetSource().getTarget();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue