SpringBoot权限管理-按钮级别权限

本文介绍了如何在Spring Boot中实现权限管理,包括自定义注解`HasPerm`、切面处理权限检查以及异常处理。通过创建`AdminController`展示了CRUD操作,并在方法上使用`@HasPerm`注解进行权限控制。当用户无权限时,会抛出`PermException`并由`MyExceptionHandler`统一处理返回无权限的错误信息。
摘要由CSDN通过智能技术生成

1.需要按钮具备权限标识

1.1.存储数据库列表

.

1.2.登录信息Redis

1.3.代码实例(以admin为例):

AdminController.java

@RestController
@RequestMapping("admin")
@RequiredArgsConstructor//使用lombok中此注解 不用写@Autowired
public class AdminController extends BaseController {


    private final AdminService adminService;
    private final AdminExcelTransfer adminExcelTransfer;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @GetMapping
    public AxiosResult<PageResult<AdminVo>> list(AdminCriteria adminCriteria) {
        PageResult<AdminVo> pageResult = adminService.searchPage(adminCriteria);
        return AxiosResult.success(pageResult);
    }

    @GetMapping("{id}")
    public AxiosResult<Admin> findById(@PathVariable Long id) {
        //根据id回显
        Admin byId = adminService.getAdminAndRoleIdsById(id);

        return AxiosResult.success(byId);
    }

    @HasPerm(perm = "admin:add")
    @PostMapping
    public AxiosResult<Void> add(@RequestBody Admin admin) {
        //bCryptPasswordEncoder: String加密
        String adminPwd = admin.getAdminPwd();
        admin.setAdminPwd(bCryptPasswordEncoder.encode(adminPwd));
        admin.setIsAdmin(false);
        return toAxios(adminService.saveAdminAndRoles(admin));
    }

    @HasPerm(perm = "admin:edit")
    @PutMapping
    public AxiosResult<Void> update(@RequestBody Admin Admin) {
        //要修改本身 还要修改角色
        //return toAxios(adminService.update(Admin));

        return toAxios(adminService.updateAdminAndRoles(Admin));
    }

    @HasPerm(perm = "admin:delete")
    @DeleteMapping("{id}")
    public AxiosResult<Void> deleteById(@PathVariable Long id) {
        return toAxios(adminService.deleteById(id));
    }

    /*
     * 批量删除
     * */
    @HasPerm(perm = "admin:batch")
    @DeleteMapping("batch/{ids}")
    public AxiosResult<Void> batchDeleteByIds(@PathVariable List<Long> ids) {
        return toAxios(adminService.batchDeleteByIds(ids));
    }
}

1.4.自定义注解,使其在按钮执行之前执行这个注解,是否有权CRUD

 HasPerm.java

/**
 * 写一个自定义注解 使其在按钮执行之前执行这个注解,是否有权CRUD
 */
@Retention(RetentionPolicy.RUNTIME) //运行时异常
@Target(ElementType.METHOD) //放在类上
public @interface HasPerm {

    String perm() default  "";
}

1.5. 创建一个切面,进行前置通知管理

package com.shangma.cn.common.permission;

import com.cn.common.http.EnumStatus;
import com.cn.common.utils.ServletUtils;
import com.cn.common.utils.TokenService;
import com.cn.domin.entity.Menu;
import com.cn.exception.PermException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
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 javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 创建一个切面
 */
@Aspect //他是一个切面
@Component //放到容器中
public class MyAspect {
    //使用token,获取登录用户信息,获取权限
    @Autowired
    private TokenService tokenService;

    /**
     * 1.前置通知
     *
     * @param joinPoint 里面需要连接点JoinPoint
     */
    @Before("pointCut()")
    public void checkPerm(JoinPoint joinPoint) {
        //Signature 他是一个接口 找到他的被继承的接口(MethodSignature) ,转换一下
        //joinPoint.getSignature()作用: 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //拿到方法,拿到这个被注解定义的方法
        Method method = signature.getMethod();
        HasPerm annotation = method.getAnnotation(HasPerm.class);

        //拿到之后,就拿到方法的注解内容,如果注解不为空
        if (annotation != null) {
            String perm = annotation.perm();

            //判断用户有没有这个权限 拿到权限信息
            List<Menu> perms = tokenService.getLoginAdmin().getPerms();

            //stream().anyMatch() 有任何一个匹配都行
            //menu.getPermission(); 可能为空 不是按钮权限 没有权限标识 的判断
            boolean b = perms.stream().anyMatch(menu -> perm.equals(menu.getPermission()));
            if (!b) {
                System.out.println("打印了: 进入权限判断了!");
                //抛出异常 防止继续执行
                throw new PermException(EnumStatus.NO_PREM);

            }

           /* //返回前端一个json信息
            String str = "{\"status\":000000,\"message\":\"无权限\"}";
            HttpServletResponse response = ServletUtils.getResponse();
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(str);*/
        }
    }

    /**
     * 2.需要一个 切入点
     */
    @Pointcut("@annotation(com.shangma.cn.common.permission.HasPerm)")
    public void pointCut() {

    }

}

1.6.权限 运行时异常

package com.cn.exception;

import com.cn.common.http.EnumStatus;

/**
 * 处理 权限验证 运行时异常
 */

public class PermException extends RuntimeException {

    private EnumStatus enumStatus;

    public PermException(EnumStatus enumStatus) {
        this.enumStatus = enumStatus;
    }

    public EnumStatus getEnumStatus() {
        return enumStatus;
    }

    public void setEnumStatus(EnumStatus enumStatus) {
        this.enumStatus = enumStatus;
    }
}

1.7.处理异常

package com.cn.exception;

import com.cn.common.http.AxiosResult;
import com.cn.common.http.EnumStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Map;

/**
 * 专门做处理异常的
 */
@RestControllerAdvice
public class MyExceptionHandler {

    /**
     * 处理权限异常
     */
    @ExceptionHandler(PermException.class)
    public AxiosResult<Void> handler(PermException e){
        EnumStatus enumStatus = e.getEnumStatus();

        return AxiosResult.error(enumStatus);

    }
}

2.附录:

2.1.枚举异常类:EnumStatus.java

package com.cn.common.http;

public enum EnumStatus {
    OK(20000,"操作成功"),
    ERROR(40000,"操作失败"),
    NO_LOGIN(40005,"未登录"),
    ACCOUNT_ERROR(40006,"用户名错误"),
    CODE_ERROR(40007,"验证码错误"),
    PWD_ERROR(40007,"密码错误"),
    CODE_LOSE(40008,"验证码失效"),
    NO_ACTIVE(40009,"用户邮箱未激活"),
    NO_PREM(40010,"无权限");

    private int status;
    private String message;

    EnumStatus(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

2.2.统一返回值类: AxiosResult.java

package com.cn.common.http;

import com.fasterxml.jackson.annotation.JsonInclude;

/*表示这个类 在转json格式字符串是,如果属性有null,则json字符串中不会有这个属性 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AxiosResult<T> {
    private int status;
    private String message;
    private T data;


    private static <T> AxiosResult<T> getAxiosResult(EnumStatus enumStatus, T data){
        return new AxiosResult<T>(enumStatus,data);
    }
    public static <T> AxiosResult<T> error(EnumStatus enumStatus) {
        return getAxiosResult(enumStatus, null);
    }
    public AxiosResult(EnumStatus enumStatus, T data){
        this.message=enumStatus.getMessage();
        this.status=enumStatus.getStatus();
        this.data=data;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    /**
     * 返回成功的方法
     */
    public static <T> AxiosResult<T> success(){
       return getAxiosResult(EnumStatus.OK,null);
    }

    public static <T> AxiosResult<T> success(T data){
        return getAxiosResult(EnumStatus.OK,data);
    }

    /**
     * 返回失败的方法
     */
    public static <T> AxiosResult<T> error(T data){
        return getAxiosResult(EnumStatus.ERROR,data);
    }

    public static <T> AxiosResult<T> error(){
        return getAxiosResult(EnumStatus.ERROR,null);
    }
}

3.效果

前端登录该用户, 点击删除, 无权限

Gitee源码地址: 暂未发布

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值