前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于切面与注解的用户权限拦截

基于切面与注解的用户权限拦截

作者头像
喜欢天文的pony站长
发布2020-06-29 12:03:59
7030
发布2020-06-29 12:03:59
举报
文章被收录于专栏:RabbitMQ实战RabbitMQ实战

思路: 定义切面,对标记有@Role(userRole)注解的方法(Api)进行拦截,验证当前登录的用户是否有该userRole角色,如果没有,则提示没有权限。否则放行。

特点: (优)简单, 稳健, 在满足需求的情况下非常适合用来做权限控制; (劣)灵活度不高,与代码耦合太高,权限不可以动态配置。

# 定义角色枚举类型User_Role

代码语言:javascript
复制
package com.futao.springmvcdemo.model.enums;

import com.futao.springmvcdemo.foundation.LogicException;
import com.futao.springmvcdemo.model.system.ErrorMessage;

/**
 * @author futao
 * Created on 2018/9/19-14:41.
 * 角色
 */
public enum User_Role {
    /**
     * 普通登录用户
     */
    Normal(1, "普通用户"),
    /**
     * 管理员用户
     */
    Admin(2, "管理员");

    private int type;
    private String description;

    User_Role(int type, String description) {
        this.type = type;
        this.description = description;
    }

    public int getType() {
        return type;
    }

    public String getDescription() {
        return description;
    }

    /**
     * 通过type来查询枚举值
     *
     * @param roleType
     * @return
     */
    public static User_Role value(int roleType) {
        if (roleType == User_Role.Normal.getType()) {
            return User_Role.Normal;
        } else if (roleType == User_Role.Admin.getType()) {
            return User_Role.Admin;
        }
        throw LogicException.le(ErrorMessage.ROLE_NOT_EXIST);
    }
}

# 定义标记注解@Role

@LoginUser该注解要求用户必须登录,具体实现可以参考前面的文章

代码语言:javascript
复制
package com.futao.springmvcdemo.annotation;

import com.futao.springmvcdemo.model.enums.User_Role;

import java.lang.annotation.*;

/**
 * @author futao
 * Created on 2018-12-13.
 * 用户权限控制
 */
@Target({
        ElementType.TYPE,
        ElementType.METHOD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@LoginUser
public @interface Role {
    /**
     * 要求的用户角色
     *
     * @return
     */
    User_Role[] value() default User_Role.Normal;
}

# 用户实体添加角色字段

该字段的值取自枚举类User_Role中的type

代码语言:javascript
复制
public class User extends BaseEntity 
    /**
     * 角色
     * {@link com.futao.springmvcdemo.model.enums.User_Role}
     */
    private int role;

# 定义拦截切面RoleInterceptor

该切面对标记了@Role()注解的类或者方法进行拦截,并在执行方法前检查用户的角色权限

代码语言:javascript
复制
package com.futao.springmvcdemo.annotation.impl.aop;

import com.futao.springmvcdemo.annotation.Role;
import com.futao.springmvcdemo.foundation.LogicException;
import com.futao.springmvcdemo.model.entity.User;
import com.futao.springmvcdemo.model.enums.User_Role;
import com.futao.springmvcdemo.model.system.ErrorMessage;
import com.futao.springmvcdemo.service.UserService;
import org.aspectj.lang.JoinPoint;
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.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;

/**
 * @author futao
 * Created on 2018-12-13.
 */
@Order(1)
@Aspect
@Component
public class RoleInterceptor {

    @Resource
    private UserService userService;

    /**
     * 切入点
     *
     * @Pointcut("@within(org.springframework.web.bind.annotation.RestController) && @annotation(org.springframework.web.bind.annotation.RestController)")
     * @Pointcut("execution(public * com.futao.springmvcdemo.controller.*.*(..))")
     * @Pointcut("execution(public * com.futao.springmvcdemo.controller..* (..)) && @annotation(org.springframework.web.bind.annotation.RestController)")
     */
    @Pointcut("@annotation(com.futao.springmvcdemo.annotation.Role)")
    public void pointCut() {

    }

    @Before("pointCut()")
    public void checkUserRole(JoinPoint point) {
        User user = userService.currentUser();
        //未登录
        if (user == null) {
            throw LogicException.le(ErrorMessage.NOT_LOGIN);
        }
        //注解打在方法上
        Role annotation = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(Role.class);
        if (annotation == null) {
            //注解打在类上
            annotation = (Role) point.getSignature().getDeclaringType().getAnnotation(Role.class);
        }
        if (annotation != null) {
            if (!Arrays.asList(annotation.value()).contains(User_Role.value(user.getRole()))) {
                throw LogicException.le(ErrorMessage.ROLE_NOT_ALLOW);
            }
        }
    }

//    @Around("pointCut()")
//    public void around(ProceedingJoinPoint point) throws Throwable {
//        System.out.println(StringUtils.repeat("-", 100));
//        point.proceed();
//    }
}

这样就OK了

# 使用

在需要进行权限拦截的接口上打上注解,并标记需要的权限

代码语言:javascript
复制
/**
     * 获取当前在线人数
     *  需要角色为admin=2的用户才可以访问该接口
     * @return
     */
    @Role(User_Role.Admin) 
    @GetMapping("onlinePeopleQuantity")
    public SingleValueResult onlinePeopleQuantity() {
        return new SingleValueResult(onlineHttpSessionListener.getOnlinePeopleQuantity().get());
    }

# 测试

# tips

使用HandlerInterceptor也可以实现同样的效果。 HandlerInterceptor拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。MethodInterceptor利用的是AOP的实现机制。在对一些普通的方法上的拦截HandlerInterceptor就无能为力了,这时候只能利用AOP的MethodInterceptor。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 喜欢天文 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 定义角色枚举类型User_Role
  • # 定义标记注解@Role
  • # 用户实体添加角色字段
  • # 定义拦截切面RoleInterceptor
  • # 使用
  • # 测试
  • # tips
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档