SpringBoot中使用自定义注解和拦截器实现简单的权限控制

SpringBoot中运用自界说注解和拦截器实现简略的权限操控

本文首发在我的个人站点:追逐日落,欢迎大家前去参观~

前言

众所周知,作为体系的最终一道防地,关于一些重要操作(crud等),后端默认接收的一切的恳求都是“不可信”的,除了确认用户登录状况之外,还要对接收的数据进行一系列的合法性校验等等,即便已经在前端页面对用户输入信息做了必定的约束。因为恳求能够假造,也或许被拦截篡改,即便在正常情况下,用户也或许因为误操作或许歹意行为发送不合法的恳求。

假如多人物体系的接口不做权限校验的话,那无疑是在“裸奔”,任何一个一般的登录用户都能调用一切的接口。

Q:什么是权限操控?

A:让特定的用户只能拜访特定的资源。

在实际项目中,假如权限操控需求杂乱的逻辑或许需求非常详尽的权限区分,或许需求凭借专门的权限结构,干流的权限结构有

  • Spring Security spring.io/projects/sp…

    Spring Security 是一个功用强大、高度可定制的身份验证和拜访操控结构。它是确保基于 Spring 的应用程序安全的事实标准。 Spring Security 是一个专注于为 Java 应用程序提供身份验证和授权的结构。与一切 Spring 项目一样,Spring Security 的真实威力在于它能够轻松扩展以满足自界说需求

  • Apache Shiro shiro.apache.org/

    Apache Shiro™ 是一个功用强大且易于运用的 Java 安全结构,可执行身份验证、授权、加密和会话管理。利用 Shiro 易于理解的 API,您能够快速、轻松地维护任何应用程序的安全–从最小的移动应用程序到最大的网络和企业应用程序。

尽管上述的结构功用非常齐备,但是关于只要两三个人物的体系来说,杀鸡焉用宰牛刀啊,经过运用SpringBoot结构提供的自界说注解和拦截器功用,能够轻松地实现对不同用户人物的拜访权限操控。

本文用例阐明:

体系有三种人物,管理员、教师、学生。

在数据库用户表中,用户类型字段以tinyint存储,3代表管理员,2代表教师,1代表学生。

功用需求:有些接口只能管理员拜访,有些接口能够让管理员和老师拜访,有些接口只能学生拜访。

界说权限常量

在项目下新建constant包,并新建接口用于界说人物权限常量

public interface UserConstant {
  int USER_TYPE_ADMIN = 3; // 管理员
  int USER_TYPE_TEACHER = 2; // 教师
  int USER_TYPE_STUDENT = 1; // 学生
  int USER_TYPE_LOGIN = 0; // 登录未认证身份用户
}

界说Access注解

新建annotation包,在包下新建一个Access注解,用于权限操控

import java.lang.annotation.*;
​
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Access {
  int[] roles() default {};
}

新建权限拦截器

/**
 * 权限拦截器
 */
@Component
public class AccessInterceptor extends HandlerInterceptorAdapter {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    if (!(handler instanceof HandlerMethod)) {
      return true;
     }
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Method method = handlerMethod.getMethod();
    Access access = method.getAnnotation(Access.class);
    //假如role是空的,阐明不需求权限,直接放行
    if (access.roles().length == 0) {
      log.info("access " + method.getName() + "role是空的");
      return true;
     }
    //假如是指定人物(们)才能拜访的权限
    //获取登录用户信息的办法
    User user = ......<补全>.......;
    //假如用户类型在权限数组中,阐明权限足够
    if (Arrays.asList(access.roles()).contains(user.getType())) {
      return true;
     } else {
      response.setStatus(403);
      return false;
     }
   }
}

注册拦截器

将权限拦截器增加到登录拦截器后边,拦截器将会在恳求处理过程中依照它们被增加的次序顺次执行。

@Configuration
public class RequestInterceptor implements WebMvcConfigurer {
  
  @Resource
  private AccessInterceptor accessInterceptor;
  
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 登录拦截器
    // registry.addInterceptor(loginInterceptor);
    registry.addInterceptor(accessInterceptor);
   }
}

在controller办法上加注解

在需求进行权限校验的接口办法上运用@Access,在注解数组中填入之前界说的常量即可,例如下面的例子表示只要学生用户和管理员用户才能够拜访接口。假如没有符号权限注解,或许注解中数组为空,则不会验证该接口恳求的权限。

@GetMapping("/hello")
@Access(roles = {UserConstant.USER_TYPE_STUDENT,UserConstant.USER_TYPE_ADMIN})
public BaseResponse<List<Activity>> hello(){
  //一致回来结果类,回来一致格局的响应
  return ResultUtil.success(activityService.list());
}

以上实现了一种在注解中枚举人物的权限操控办法,能够实现简略而灵敏的权限操控,维护我们的应用程序免受未经授权的拜访。这样运用数组界说注解,优点是自界说程度高,能够指定哪(几)个人物,然后更加精细的操控拜访权限,缺点是用户人物较多时,注解增加会比较费事。

假如权限区分是分层级的话(例如:超级无敌管理员>超级管理员>一般管理员,高权限用户能够向下拜访低权限用户的一切接口,低权限用户不能向上拜访),能够将注解里的roles改成整形,并修正权限拦截器,将判定条件修正成比较权限值的巨细,只要用户的权限的数值高于接口权限就放行。