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

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

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

特点:


(优)简单, 稳健, 在满足需求的情况下非常适合用来做权限控制;

(劣)灵活度不高,与代码耦合太高,权限不可以动态配置。


# 定义角色枚举类型User_Role

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该注解要求用户必须登录,具体实现可以参考前面的文章

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

public class User extends BaseEntity 
    /**
     * 角色
     * {@link com.futao.springmvcdemo.model.enums.User_Role}
     */
    private int role;

# 定义拦截切面RoleInterceptor


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

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了


# 使用


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

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


# 测试

image.png

image.png

image.png

image.png

# tips


使用HandlerInterceptor也可以实现同样的效果。

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

相关文章
优雅的日志记录:自定义注解结合AOP实现
优雅的日志记录:自定义注解结合AOP实现
64 0
SpringMVC自定义注解验证登陆拦截
这里业务场景需要,所有的请求都需要登录验证。个别通用业务不需要登录拦截。注解方式替代原有的if判断。
118 0
SpringMVC自定义注解验证登陆拦截
|
缓存 开发框架 安全
AOP的另类用法 (权限校验&&自定义注解)
告别了OOP编程, 迎来了一个新的AOP编程时代👍👍👍, 最近有同学问我AOP除了写日志还能干什么, 其实AOP能干的事情挺多的, 可能只是他们写的代码中暂时用不到. 其实如果当我们写一些简单的程序的时候, SpringSecurity完全用不到的时候, 就可以使用AOP与自定义注解来为角色的访问权限进行鉴定, 绝对比Security更轻量👉👉👉 我们在接触框架的时候经常会用到注解, 但是我们自己自定义注解的情况比较少, 一般都是配合切面编程使用, 一起来看看吧
207 0
|
SQL Java 数据库连接
注解方式实现AOP的接口控制
注解方式实现AOP的接口控制
注解方式实现AOP的接口控制
|
Java 数据库 Spring
基于注解的用户权限拦截Spring HandlerInterceptor
基于注解的用户权限拦截Spring HandlerInterceptor
基于注解的用户权限拦截Spring HandlerInterceptor
|
Java 数据安全/隐私保护 Spring
动态验签与用户权限拦截(Spring HandlerInterceptor)
动态验签与用户权限拦截(Spring HandlerInterceptor)
动态验签与用户权限拦截(Spring HandlerInterceptor)
|
数据安全/隐私保护
自定义注解+拦截器实现权限控制
今天刚学习了通过自定义注解+拦截器实现权限控制,自己花了点时间整理,发到网站同网友交流分享。
180 0
自定义注解+拦截器实现权限控制