SpringBoot 基于AOP实现Controller层用户角色权限控制
程序员文章站
2024-03-02 13:01:40
...
一、需求
在Controller层基于AOP实现用户角色权限校验
某接口仅允许
1.角色id为1-普通用户、2系统管理员
2.用户id为1 的用户访问
1、普通的实现方案
/**
* 登录 将用户信息写入session
* @param username 用户名
* @param password 密码
* @param httpSession
* @return
*/
@PostMapping(value = "/user/login")
public Result<Void> login(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession httpSession){
//登录成功
UserData userData = new UserData();
userData.setId(1);
userData.setRole(2);
httpSession.setAttribute("userData",userData);
return Result.of(200, "success");
}
@Autowired
private HttpServletRequest request;
/**
* 从session中获取登录用户的信息
* @return
*/
public UserData getUserInfo() {
return (UserData)request.getSession().getAttribute("userData");
}
/**
* 普通的实现方案
* @return
*/
@PostMapping(value = "/hello1")
public Result<String> sayHelloV1(){
UserData userData = this.getUserInfo();
if(userData == null){
return Result.of(403, "未登录");
}
Integer role = userData.getRole();
if(!RoleEnums.ADMIN.getValue().equals(role)
&&!RoleEnums.NORMAL.getValue().equals(role)){
return Result.of(401, "无权限");
}
Integer uid = userData.getId();
if(uid != 1){
return Result.of(401, "无权限");
}
return Result.of(200, "success","hello world");
}
1.1使用到的类
Result.java
package com.shengsheng.domain;
import java.io.Serializable;
/**
* @author shengshenglalala
* 响应体
*/
public class Result<T> implements Serializable {
private Integer status = 0;
private String message = "";
private T data;
public Result(Integer status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
public Result(Integer status, String message) {
this.status = status;
this.message = message;
}
public Result(Integer status) {
this.status = status;
}
public Result() {
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer 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> Result<T> of(Integer status, String message, T data) {
return new Result<T>(status, message, data);
}
public static <T> Result<T> of(Integer status, String message) {
return Result.of(status, message, null);
}
}
UserData.java
package com.shengsheng.domain;
/**
* description:
*
* @author shengshenglalala
* @date 2021/1/21 19:41
*/
public class UserData {
/**
* 用户ID
*/
private Integer id;
/**
* 用户角色id
*/
private Integer role;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getRole() {
return role;
}
public void setRole(Integer role) {
this.role = role;
}
}
RoleEnums.java
package com.shengsheng;
/**
* 用户角色枚举值
* @author shengshenglalala
*/
public enum RoleEnums {
/**
* 普通用户
*/
NORMAL(1, "普通用户"),
/**
* 系统管理员
*/
ADMIN(2,"系统管理员");
private final Integer value;
private final String name;
RoleEnums(Integer value, String name){
this.value = value;
this.name = name;
}
public Integer getValue(){
return value;
}
public String getName(){
return name;
}
/**
* 通过属性值获取属性名
* @param v 要查询的属性值
* @return 属性名
*/
public static String getName(Integer v){
for(RoleEnums item :values()){
if (item.getValue().equals(v))
{
return item.getName();
}
}
return "";
}
}
普通的实现方案中需要写大量的冗余代码、针对每个接口都需要进行重复的角色权限校验。
2.基于注解AOP的实现方案
/**
* 仅角色id为2用户id为1的用户可以登录
*/
@RolePermissionVerificationAnno(roleIdList = {1,2},userIdList = {1})
@PostMapping(value = "/hello")
public Result<String> sayHello(){
return Result.of(200, "success","hello world");
}
2.1使用的注解
RolePermissionVerificationAnno.java
package com.shengsheng.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在Controller中的方法上使用该注解时,校验该用户是否是系统指定的角色id或者用户id,如果不是则直接响应无权操作
* 请至少配置roleIdList或者userIdList
*
* @author shengshenglalala
*/
// 方法注解
@Target(ElementType.METHOD)
// 运行时可见
@Retention(RetentionPolicy.RUNTIME)
public @interface RolePermissionVerificationAnno {
/**
* 有权限访问的角色id 配置了之后只有当前指定的角色id才可以访问该接口
*/
long[] roleIdList() default {};
/**
* 有权限访问的用户id 配置了之后只有当前指定的用户id才可以访问该接口
*/
long[] userIdList() default {};
}
RolePermissionVerificationAspect.java
package com.shengsheng.aop;
import com.shengsheng.domain.Result;
import com.shengsheng.domain.UserData;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* 用户角色权限控制的AOP实现
*
* @author shengshenglalala
*/
@Component
@Aspect
public class RolePermissionVerificationAspect {
@Pointcut("@annotation(com.shengsheng.aop.RolePermissionVerificationAnno)")
public void rolePermissionCheckPointCut() {
}
/**
* 环绕通知记录校验角色权限
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("rolePermissionCheckPointCut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
// 获取正在访问的方法
Method executionMethod = methodSignature.getMethod();
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
Object result;
String message = "您无权进行此操作";
if (executionMethod.getReturnType().getTypeName().contains(Result.class.getSimpleName())) {
result = Result.of(404, message);
} else {
result = message;
}
if(sra == null){
return result;
}
HttpServletRequest request = sra.getRequest();
Integer userId = null;
Integer roleId = null;
UserData userData = (UserData) request.getSession().getAttribute("userData");
if (userData != null) {
userId = userData.getId();
roleId = userData.getRole();
}
RolePermissionVerificationAnno annotation = executionMethod.getAnnotation(RolePermissionVerificationAnno.class);
//获取注解中的types字段
long[] roleIdList = annotation.roleIdList();
long[] userIdList = annotation.userIdList();
//该用户是否有访问权限
boolean flag = false;
//是否需要进行校验 当用户列表和角色列表同时为空时不进行校验
boolean checkFlag = false;
if (roleIdList.length > 0) {
//需要进行用户角色权限校验
checkFlag = true;
if (roleId != null) {
for (long role : roleIdList) {
if (role == roleId) {
flag = true;
break;
}
}
}
}
if (userIdList.length > 0) {
checkFlag = true;
if (userId != null) {
for (long uid : userIdList) {
if (uid == userId) {
flag = true;
break;
}
}
}
}
if (checkFlag) {
//需要进行校验
if (flag) {
//校验通过
result = pjp.proceed();
}
}else {
//不需要进行校验
result = pjp.proceed();
}
return result;
}
}
下一篇: Android View如何绘制