All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ink.huaxun.authority.aspect.RequiresPermissionsAspect Maven / Gradle / Ivy

package ink.huaxun.authority.aspect;

import ink.huaxun.authority.annotation.RequiresPermissions;
import ink.huaxun.redis.util.RedisUtil;
import ink.huaxun.util.HttpServletUtil;
import ink.huaxun.util.JwtUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author zhaogang
 * @description 权限切面
 * @date 2023/2/7 17:48
 */
@Aspect
@Component
public class RequiresPermissionsAspect {

    /**
     * token的头
     */
    @Value("${token.header}")
    private String header;

    /**
     * redis的用户权限key
     */
    @Value("${redis.permission-user-id}")
    private String permissionUserIdKey;

    /**
     * uri前缀
     */
    private static final String URI_PREFIX = "/";

    /**
     * uri后缀
     */
    private static final String URI_SUFFIX = "/";

    /**
     * uri分隔符
     */
    private static final String URI_SEPARATOR = "/";

    /**
     * 权限分隔符
     */
    private static final String PERMISSION_SEPARATOR = ":";

    /**
     * PathVariable的前缀
     */
    private static final String PATH_VARIABLE_PREFIX = "{";

    /**
     * 编辑权限
     */
    private static final String EDIT = "edit";

    /**
     * 查看权限
     */
    private static final String GET = "get";

    /**
     * 切面操作
     */
    @Around("@annotation(ink.huaxun.authority.annotation.RequiresPermissions)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        RequiresPermissions annotation = method.getAnnotation(RequiresPermissions.class);
        if (annotation == null) {
            return point.proceed();
        }

        HttpServletRequest request = HttpServletUtil.getRequest();
        if (request == null) {
            throw new AuthorizationException("request is null!");
        }

        // 尝试在这里获得请求url
        String[] authority = annotation.value();
        if (ArrayUtils.isEmpty(authority)) {
            String uri = request.getRequestURI();
            authority = this.uriToPermission(uri, method);
        }
        String token = request.getHeader(header);
        if (!this.has(authority, token)) {
            throw new AuthorizationException("无操作权限");
        }
        return point.proceed();
    }

    /**
     * 判断登录用户是否有权限
     */
    private boolean has(String[] authority, String token) {
        String userId = JwtUtil.getId(token);
        String key = permissionUserIdKey + userId;
        for (String permission : authority) {
            Boolean value = RedisUtil.hasHashItem(key, permission);
            if (BooleanUtils.isTrue(value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * uri转权限
     */
    private String[] uriToPermission(String uri, Method method) {
        if (StringUtils.isBlank(uri)) {
            return ArrayUtils.EMPTY_STRING_ARRAY;
        }
        String value = this.getMappingValue(method);
        uri = this.removePathVariable(value, uri, method.getName());
        uri = uri.replaceFirst(URI_PREFIX, StringUtils.EMPTY);
        String permission = uri.replaceAll(URI_SEPARATOR, PERMISSION_SEPARATOR);
        String[] subsidiary = this.getSubsidiaryPermission(permission);
        return ArrayUtils.addAll(subsidiary, permission);
    }

    /**
     * 获取注解中的value值
     */
    private String getMappingValue(Method method) {
        String[] value = this.getMappingValues(method);
        if (ArrayUtils.isEmpty(value)) {
            return StringUtils.EMPTY;
        }
        return value[0];
    }

    /**
     * 获取注解中的value数组
     */
    private String[] getMappingValues(Method method) {
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        if (getMapping != null) {
            return getMapping.value();
        }
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        if (postMapping != null) {
            return postMapping.value();
        }
        PutMapping putMapping = method.getAnnotation(PutMapping.class);
        if (putMapping != null) {
            return putMapping.value();
        }
        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
        if (deleteMapping != null) {
            return deleteMapping.value();
        }
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        if (requestMapping != null) {
            return requestMapping.value();
        }
        return ArrayUtils.EMPTY_STRING_ARRAY;
    }

    /**
     * 删除PathVariable参数,补充方法名作为权限值
     */
    private String removePathVariable(String value, String uri, String methodName) {
        // 排除路由为"/"的影响
        value = value.replaceFirst(URI_PREFIX, StringUtils.EMPTY);
        // 排除路由以"/"结尾的影响
        if (uri.endsWith(URI_SUFFIX)) {
            uri = uri.substring(0, uri.lastIndexOf(URI_SUFFIX));
        }
        // 当路由为空或仅有PathVariable情况下,需要补充方法名作为权限值
        if (StringUtils.isBlank(value)) {
            return uri + URI_SEPARATOR + methodName;
        }
        // 正常路由情况下,直接使用uri
        if (!value.contains(PATH_VARIABLE_PREFIX)) {
            return uri;
        }
        // PathVariable的情况下,需要去除PathVariable部分的uri(最后一段/{xxx})
        int start = 0;
        while ((start = value.indexOf(PATH_VARIABLE_PREFIX, start)) >= 0) {
            start += PATH_VARIABLE_PREFIX.length();
            uri = uri.substring(0, uri.lastIndexOf(URI_SEPARATOR));
        }
        // uri最后一段相同时,默认合并(不允许uri出现连续相同字符串)
        if (uri.endsWith(URI_SEPARATOR + methodName)) {
            return uri;
        }
        return uri + URI_SEPARATOR + methodName;
    }

    /**
     * 获取额外的附属权限
     */
    private String[] getSubsidiaryPermission(String permission) {
        // 请求查看方法时,如果有编辑权限,则视为通过
        if (permission.endsWith(PERMISSION_SEPARATOR + GET)) {
            String subsidiary = permission.substring(0, permission.lastIndexOf(GET)) + EDIT;
            return new String[]{subsidiary};
        }
        return null;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy