4)SpringBoot-自定义注解控制权限

4)SpringBoot-自定义注解控制权限

引入springboot-aop依赖

<!-- Spring Boot Starter AOP -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

定义权限注解

@Target({ElementType.TYPE, ElementType.METHOD}) 表示允许在类和方法上使用该注解

package com.permission_demo.annotation;


import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Permission {
    /**
     * 权限点
     */
    String code() default "";

    /**
     * 权限点描述
     */
    String desc() default "";
}

定义aop切面

关于aop可从这篇文章了解 https://blog.youkuaiyun.com/sql2008help/article/details/116424839

package com.permission_demo.aop;

import com.permission_demo.annotation.Permission;
import com.permission_demo.exception.PermissionDeniedException;
import com.permission_demo.service.PermissionService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

@Aspect
@Component
public class PermissionAspect {

    @Autowired
    private PermissionService permissionService;


    // 定义切点,匹配所有带有@Permission注解的类和方法
    @Pointcut(value = "@within(com.permission_demo.annotation.Permission) || @annotation(com.permission_demo.annotation.Permission)")
    public void pointCut() {
    }

    //环绕通知
    @Around("pointCut()")
    public Object aroundPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取类上的权限注解
        Class<?> targetClass = joinPoint.getTarget().getClass();
        Permission classPermission = targetClass.getAnnotation(Permission.class);

        // 如果类上没有定义权限直接放行
        if (Objects.isNull(classPermission)) {
            return joinPoint.proceed();
        }

        // 2. 获取方法上的权限注解
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Permission methodPermission = method.getAnnotation(Permission.class);
        if (Objects.isNull(methodPermission)) {
            return joinPoint.proceed();
        }

        if (!permissionService.hasPermission(classPermission.code() + "$" + methodPermission.code())) {
            throw new PermissionDeniedException("没有权限访问!");
        }

        return joinPoint.proceed();
    }
}

权限校验类:

package com.permission_demo.service;

import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

@Component
public class PermissionService {

    // 实际从登录成功的用户数据中获取该用户所有角色的权限并集
    private static Set<String> CURRENT_USER_PERMISSION = new HashSet<>();
    static {
        CURRENT_USER_PERMISSION.add("user_manage$view");
    }

    public boolean hasPermission(String permission) {
        return CURRENT_USER_PERMISSION.contains(permission);
    }
}

使用自定义注解

如下:

package com.permission_demo.controller;

import com.permission_demo.annotation.Permission;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/user")
@Permission(code = "user_manage",desc = "用户管理")
public class UserController {

    @Permission(code = "add",desc = "新增")
    @GetMapping(value = "/add")
    public String add(){
        return "新增用户";
    }

    @Permission(code = "view",desc = "查看")
    @GetMapping(value = "/view")
    public String view(){
        return "查看用户";
    }

}

全局异常处理

package com.permission_demo.handler;

import com.permission_demo.exception.PermissionDeniedException;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(PermissionDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ErrorResponse handlePermissionDenied(PermissionDeniedException e) {
        return new ErrorResponse(403, "FORBIDDEN", e.getMessage());
    }

    @Getter
    static class ErrorResponse {
        // Getters
        private int status;
        private String error;
        private String message;

        public ErrorResponse(int status, String error, String message) {
            this.status = status;
            this.error = error;
            this.message = message;
        }

    }
}

测试

http://127.0.0.1:8093/user/view 可正常访问

http://127.0.0.1:8093/user/add 被拦截

上述代码路径:https://gitee.com/husong_zone/permission_demo

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值