springboot+自定义注解+AOP实现权限控制(二)

文末有下载链接!!!

在上文《springboot+自定义注解+AOP实现权限控制(一)》中,简单介绍了自定义注解和AOP的作用,本文开始从代码角度详细解释该如何使用。

实现效果

    我想要这样一个效果,如:在某个接口加上自定义的权限注解,表示只有拥有此权限的用户才能访问。如A用户访问到add接口,如果有add接口的权限,允许访问,否则返回权限不足信息并不允许访问。其中返回信息为了美化,我通过全局异常来捕获。

设计思路:

1. 用户分为四种权限,管理员,添加和修改员,删除员,普通用户(只有查看权限);

2. 通过访问product类的增删改查接口来验证权限是否成功;

3. 流程:

(1)接口添加对应的注解,如add接口设置@Permission(value=add),表示拥有add权限的人才能访问

(2)用户登录后产生一个token,token包含用户的id信息(此步省略。假设token即userId)。

(3)访问接口,通过AOP拦截到此用户的登录信息,到数据库查询该用户的对应权限permissons

(4)查看permissons中是否包含注解的属性值value=add,

(5)如果包含,允许访问;否则抛出异常,不允许访问。

4. 关键点

(1)自定义权限注解如何设计

(2)AOP的切面如何编写

(3)用户-角色-权限如何设计

一. 搭建基本结构

二. 设计用户-角色-权限表结构

添加测试用户,userId=1为管理员,userId=2可以添加或修改,userId=3可以删除,其他只有查看权限。

用户表-角色表-权限表分别用中间表来关联外键。

三. 自定义注解

首先我定义了几个常量表示CRUD的权限

public class PermissionConsts {

    /**
     * 查看权限
     */
    public static final String R = "R_PERMISSION";

    /**
     * 添加权限
     */
    public static final String C = "C_PERMISSION";

    /**
     * 修改权限
     */
    public static final String U = "U_PERMISSION";

    /**
     * 删除权限
     */
    public static final String D = "D_PERMISSION";
}

自定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyPermission {

    /**
     * 默认只有查看权限
     * @return
     */
    String value() default PermissionConsts.R;
}

四. AOP切面

@Aspect
@Component
@Slf4j
public class PermissionAspect {

    @Resource
    private UserDao userDao;

    /**
     * 目标方法
     */
    @Pointcut("@annotation(com.mac.annotation.MyPermission)")
    private void permission() {

    }

    /**
     * 目标方法调用之前执行
     */
    @Before("permission()")
    public void doBefore() {
        System.out.println("================== step 2: before ==================");
    }

    /**
     * 目标方法调用之后执行
     */
    @After("permission()")
    public void doAfter() {
        System.out.println("================== step 4: after ==================");
    }

    /**
     * 环绕
     * 会将目标方法封装起来
     * 具体验证业务数据
     */
    @Around("permission()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("================== step 1: around ==================");
        long startTime = System.currentTimeMillis();
        /*
         * 获取当前http请求中的token
         * 解析token :
         * 1、token是否存在
         * 2、token格式是否正确
         * 3、token是否已过期(解析信息或者redis中是否存在)
         * */
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("非法请求,无效token");
        }
        // 校验token的业务逻辑

        //假设token里只是一个userId,查询到他有删除和查看的权限,没有添加和修改的权限
        // 解析token之后,获取当前用户的账号信息,查看它对应的角色和权限信息
        //String userId = parse(token);
        List<UserPermissionDto> codes = userDao.findPermissionCodeByUserId(token);
        List<String> permissionCodes = codes.stream().map(UserPermissionDto::getPermissionCode).collect(Collectors.toList());
        /*
         * 获取注解的值,并进行权限验证
         * */
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        MyPermission myPermission = method.getAnnotation(MyPermission.class);

        String value = myPermission.value();
        // 将注解的值和token解析后的值进行对比,查看是否有该权限,如果权限通过,允许访问方法;否则不允许,并抛出异常
        if(!permissionCodes.contains(value)){
            throw new RuntimeException("对不起,您没有权限访问!");
        }
        // 执行具体方法
        Object result = proceedingJoinPoint.proceed();

        long endTime = System.currentTimeMillis();

        /*
         * 记录相关执行结果
         * 可以存入MongoDB 后期做数据分析
         * */
        // 打印请求 url
        System.out.println("URL            : " + request.getRequestURL().toString());
        // 打印 Http method
        System.out.println("HTTP Method    : " + request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        System.out.println("controller     : " + proceedingJoinPoint.getSignature().getDeclaringTypeName());
        // 调用方法
        System.out.println("Method         : " + proceedingJoinPoint.getSignature().getName());
        // 执行耗时
        System.out.println("cost-time      : " + (endTime - startTime) + " ms");

        return result;

    }

}

五. 接口添加注解

@RestController
@RequestMapping(value = "/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping(value = "/findAll")
    @MyPermission(value = PermissionConsts.R)
    public Result<List<ProductDto>> findAll(){
        return productService.findAll();
    }

    @PostMapping(value = "/add")
    @MyPermission(value = PermissionConsts.C)
    public Result<Boolean> add(@RequestBody ProductAddParam productParam){
        return productService.add(productParam);
    }

    @PostMapping(value = "/update")
    @MyPermission(value = PermissionConsts.U)
    public Result<Boolean> update(@RequestBody ProductUpdateParam productParam){
        return productService.update(productParam);
    }

    @GetMapping(value = "/delete")
    @MyPermission(value = PermissionConsts.D)
    public Result<Boolean> delete(@RequestParam Long id){
        return productService.delete(id);
    }
    
}

六. 其他代码可以查看文末的下载链接

七. 测试

1. 查看接口。

测试token=1到6(后期可用jwt优化token,这里简单设置为token=userId)的用户,发现数据库每个用户都可以访问。但userId不存在的用户,如token=100,则无法访问接口。

2. 添加/修改接口

添加/修改产品,userId=3的用户无法删除,因为数据库查询到权限不足;只有userId=2的用户可以添加/修改

3. 删除接口

删除productId=1的产品,userId=2的用户无法删除,因为数据库查询到权限不足;只有userId=1或3的用户可以删除

 

github链接:https://github.com/laoyog/customize-permission

CSDN链接:https://download.csdn.net/download/byteArr/12104797

  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源介绍】 基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip基于springboot+mvc+freemarker+aop实现校友信息管理系统.zip 【备注】 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载,欢迎沟通,互相学习,共同进步!提供答疑!
【资源说明】 1、基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值