SpringBoot使用自定义注解实现权限拦截的示例

本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下:

HandlerInterceptor(处理器拦截器)

常见使用场景

  • 日志记录: 记录请求信息的日志, 以便进行信息监控, 信息统计, 计算PV(page View)等
  • 性能监控:
  • 权限检查:
  • 通用行为:

使用自定义注解实现权限拦截

首先HandlerInterceptor了解

在HandlerInterceptor中有三个方法:

public interface HandlerInterceptor {

  // 在执行目标方法之前执行
  boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)throws Exception;

  // 执行目标方法之后执行
  void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;

  // 在请求已经返回之后执行
  void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;

}

在以上注释中已经写明执行顺序, 测试及测试结果如下:

public class TestInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("preHandler");
    return true;
  }

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    System.out.println("postHandler");
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("afterCompletion");
  }
}

结果:

preHandler
postHandler
afterCompletion

如何配置拦截器后面讲:

下面来讲讲这个拦截器是拦截的什么?

方法拦截器HandlerInterceptor

我们使用SpringMVC都知道SpringMVC是基于方法的请求处理, 和Struts2有明显区别(我是这么理解的), 并且Controller是单例模式, 所有请求都是从DispatcherServlet来调用请求url对应的方法的(处理器映射器的功能), 那么它是一个方法拦截器, 如何知道呢?

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  System.out.println(handler.getClass());
  return true;
}

执行结果:

class org.springframework.web.method.HandlerMethod

已经看到拦截器如何工作, 并且知道它是方法级别的拦截器, 那么接下来看看如何配置拦截器, 让它在服务器运行期间起作用

实现HandlerInterceptor

实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类
HandlerInterceptorAdapter适配器是对HandlerInterceptor接口做了默认实现, 这种适配器模式, 是为了方便开发者只去想要复写方法, 其他方法采取默认措施.

上面的TestInterceptor就是一个Demo, 具体可以按需求在我们想要拦截的位置进行相应的逻辑处理

配置拦截器

从Spring4.x开始, 就支持注解配置具体是使用@Configuration注解标注一个普通类, 使该类成为配置类, 可以在该类中定义Bean, 以及注入一些配置参数等.

首先, 我们要配置拦截器,就需要想SpringMvc的拦截链中取注入我们的拦截器, 这样才能请求进来时去拦截我们想要拦截的请求, 所以, 需要我们新建一个普通类, 使用@Configuration注解标注在类名上, 并且让该类继承WebMvcConfigurerAdapter,为什么不实现WebMvcConfigurer接口呢? 因为方法太多,我们不需要复写其中所有方法...

下面让我们新建一个配置类, 来配置我们的拦截器

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {

  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**");
  }
}

复写addInterceptors之后, 当我们的服务器启动时, 会自动调用这个方法, 参数怎么传我们都不用管(目前是java初级阶段, 没空研究Spring深层原理), 我们只要知道这个方法一定会被调用就行了.

我们直接new一个自定义拦截器, 注册到整个拦截链中, 并且制定拦截路径, 这样当满足请求url拦截配置时, 我们的自定义拦截器就会执行相应的方法了.

拦截方法是非常灵的, 除了拦截配置的, 也可以拦截非匹配的, 也可以根据正则表达式拦截请求

至此, 我们的拦截器就完成了, 接下来自定义权限相关注解

自定义权限注解

定义一个@interface类

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

  String[] value() default {};

  String[] authorities() default {};

  String[] roles() default {};

}

@Target注解是标注这个类它可以标注的位置:

常用的元素类型(ElementType):

public enum ElementType {
  /** Class, interface (including annotation type), or enum declaration */
  // TYPE类型可以声明在类上或枚举上或者是注解上
  TYPE,
  /** Field declaration (includes enum constants) */
  // FIELD声明在字段上
  FIELD,
  /** Method declaration */
  // 声明在方法上
  METHOD,
  /** Formal parameter declaration */
  // 声明在形参列表中
  PARAMETER,
  /** Constructor declaration */
  // 声明在构造方法上
  CONSTRUCTOR,
  /** Local variable declaration */
  // 声明在局部变量上
  LOCAL_VARIABLE,
  /** Annotation type declaration */
  ANNOTATION_TYPE,
  /** Package declaration */
  PACKAGE,
  /**
   * Type parameter declaration
   *
   * @since 1.8
   */
  TYPE_PARAMETER,
  /**
   * Use of a type
   *
   * @since 1.8
   */
  TYPE_USE
}

@Retention注解表示的是本注解(标注这个注解的注解保留时期)

public enum RetentionPolicy {
  /**
   * Annotations are to be discarded by the compiler.
   */
  // 源代码时期
  SOURCE,
  /**
   * Annotations are to be recorded in the class file by the compiler
   * but need not be retained by the VM at run time. This is the default
   * behavior.
   */
  // 字节码时期, 编译之后
  CLASS,
  /**
   * Annotations are to be recorded in the class file by the compiler and
   * retained by the VM at run time, so they may be read reflectively.
   *
   * @see java.lang.reflect.AnnotatedElement
   */
   // 运行时期, 也就是一直保留, 通常也都用这个
  RUNTIME
}

@Documented是否生成文档的标注, 也就是生成接口文档是, 是否生成注解文档

注解说完了, 下面需要到对应的controller的方法中取添加注解, 配置该方法允许的权限

在方法上配置权限

@RestController
public class HelloController {

  @RequestMapping(value = "/admin", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
  // 配置注解权限, 允许身份为admin, 或者说允许权限为admin的人访问
  @Access(authorities = {"admin"})
  public String hello() {
    return "Hello, admin";
  }
}

编写权限逻辑

// 自定义一个权限拦截器, 继承HandlerInterceptorAdapter类
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {

  // 在调用方法之前执行拦截
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethod
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    // 从方法处理器中获取出要调用的方法
    Method method = handlerMethod.getMethod();
    // 获取出方法上的Access注解
    Access access = method.getAnnotation(Access.class);
    if (access == null) {
    // 如果注解为null, 说明不需要拦截, 直接放过
      return true;
    }
    if (access.authorities().length > 0) {
      // 如果权限配置不为空, 则取出配置值
      String[] authorities = access.authorities();
      Set<String> authSet = new HashSet<>();
      for (String authority : authorities) {
      // 将权限加入一个set集合中
        authSet.add(authority);
      }
      // 这里我为了方便是直接参数传入权限, 在实际操作中应该是从参数中获取用户Id
      // 到数据库权限表中查询用户拥有的权限集合, 与set集合中的权限进行对比完成权限校验
      String role = request.getParameter("role");
      if (StringUtils.isNotBlank(role)) {
        if (authSet.contains(role)) {
        // 校验通过返回true, 否则拦截请求
          return true;
        }
      }
    }
    // 拦截之后应该返回公共结果, 这里没做处理
    return false;
  }

}

至此, 我们启动服务器, 访问接口, 就能看到效果, 这里不做示范了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot中使用 Spring Security 构建权限系统的示例代码

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. 权限控制是非常常见的功能,在各种后台管理里权限控制更是重中之重.在Spring Boot中使用 Spring Security 构建权限系统是非常轻松和简单的.下面我们就来快速入门 Spring Security .在开始前我们需要一对

  • spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制

    1.添加maven依赖(先安装好cas-server-3.5.2,安装步骤请查看本文参考文章) <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>

  • 详解关于springboot-actuator监控的401无权限访问

    今天心血来潮看一下spring监控 访问/beans 等敏感的信息时候报错 Tue Mar 07 21:18:57 GMT+08:00 2017 There was an unexpected error (type=Unauthorized, status=401). Full authentication is required to access this resource. application.properties添加配置参数 management.security.enabled=

  • SpringBoot使用自定义注解实现权限拦截的示例

    本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下: HandlerInterceptor(处理器拦截器) 常见使用场景 日志记录: 记录请求信息的日志, 以便进行信息监控, 信息统计, 计算PV(page View)等 性能监控: 权限检查: 通用行为: 使用自定义注解实现权限拦截 首先HandlerInterceptor了解 在HandlerInterceptor中有三个方法: public interface HandlerInterceptor { //

  • SpringBoot通过自定义注解实现日志打印的示例代码

    前言 在我们日常的开发过程中通过打印详细的日志信息能够帮助我们很好地去发现开发过程中可能出现的Bug,特别是在开发Controller层的接口时,我们一般会打印出Request请求参数和Response响应结果,但是如果这些打印日志的代码相对而言还是比较重复的,那么我们可以通过什么样的方式来简化日志打印的代码呢? SpringBoot 通过自定义注解实现权限检查可参考我的博客:SpringBoot 通过自定义注解实现权限检查 正文 Spring AOP Spring AOP 即面向切面,是对OO

  • SpringBoot如何通过自定义注解实现权限检查详解

    前言 最近开发了一个接口,完成后准备自测时,却被拦截器拦截了,提示:(AUTH-NO)未能获得有效的请求参数!怎么会这样呢? 于是我全局搜了这个提示语,结果发现它被出现在一个Aspect类当中了,并且把一个 @interface 作为了一个切点,原来这里利用了Spring AOP面向切面的方式进行权限控制. SpringBoot通过自定义注解实现日志打印可参考:SpringBoot通过自定义注解实现日志打印 正文 Spring AOP Spring AOP 即面向切面,是对OOP面向对象的一种延

  • SpringBoot通过自定义注解实现配置类的自动注入的实现

    目录 前言 实现思路 自定义配置类读取配置 自定义注解 创建子配置Bean 通过反射进行people bean的注入 使用 效果 回顾 延伸 前言 SpringBoot中通过@ConfigurationProperties或@Value注解就可以获取配置文件中的属性定义并绑定到Java Bean或属性上,这也是我们平常使用最多的一种方式.但是小胖在开发过程中就遇到一个问题:在做MQ的开发中,配置文件中会配置多个生产者分别提供不同的业务能力,如果通过@ConfigurationProperties

  • SpringBoot中自定义注解实现参数非空校验的示例

    前言 由于刚写项目不久,在写 web 后台接口时,经常会对前端传入的参数进行一些规则校验,如果入参较少还好,一旦需要校验的参数比较多,那么使用 if 校验会带来大量的重复性工作,并且代码看起来会非常冗余,所以我首先想到能否通过一些手段改进这点,让 Controller 层减少参数校验的冗余代码,提升代码的可阅读性. 经过阅读他人的代码,发现使用 annotation 注解是一个比较方便的手段,SpringBoot 自带的 @RequestParam 注解只会校验请求中该参数是否存在,但是该参数是

  • SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码

    目录 为什么要限流 限流背景 实现限流 1.引入依赖 2.自定义限流注解 3.限流切面 4.写一个简单的接口进行测试 5.全局异常拦截 6.接口测试 为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以,我们可以通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统或避免不必要的资源浪费,一旦达到限制速率则可以拒绝服务.排队或等待

  • Spring Boot 通过AOP和自定义注解实现权限控制的方法

    本文介绍了Spring Boot 通过AOP和自定义注解实现权限控制,分享给大家,具体如下: 源码:https://github.com/yulc-coding/java-note/tree/master/aop 思路 自定义权限注解 在需要验证的接口上加上注解,并设置具体权限值 数据库权限表中加入对应接口需要的权限 用户登录时,获取当前用户的所有权限列表放入Redis缓存中 定义AOP,将切入点设置为自定义的权限 AOP中获取接口注解的权限值,和Redis中的数据校验用户是否存在该权限,如果R

  • SpringBoot通过自定义注解实现参数校验

    目录 1. 为什么要进行参数校验 2. 如何实现参数校验 3. 注解实现参数校验 4. 自定义注解实现参数校验 1. 为什么要进行参数校验 在后端进行工作时,需要接收前端传来的数据去数据库查询,但是如果有些数据过于离谱,我们就可以直接把它pass掉,不让这种垃圾数据接触数据库,减小数据库的压力. 有时候会有不安分的人通过一些垃圾数据攻击咱们的程序,让咱们的服务器或数据库崩溃,这种攻击虽然低级但不得不防,就像QQ进行登录请求时,它们向后端发送 账号=123,密码=123 的数据,一秒钟还发1w次,

  • SpringBoot使用自定义注解实现数据脱敏过程详细解析

    目录 前言 一.引入hutool工具类 二.定义常用需要脱敏的数据类型的枚举 三.定义脱敏方式枚举 四.自定义脱敏的注解 五.自定义Jackson的序列化方式 六.使用 七.脱敏效果 前言 对于某些接口返回的信息,涉及到敏感数据的必须进行脱敏操作,例如银行卡号.身份证号.手机号等,脱敏方式有多种方式.可以修改SQL语句,也可以写硬代码,也可以修改JSON序列化,这里介绍通过修改Jackson序列化方式实现数据脱敏. 一.引入hutool工具类 maven: <dependency> <g

  • SpringBoot通过自定义注解与异步来管理日志流程

    目录 一.前言 二.基础环境 1. 导入依赖 2. 编写yml配置 三.数据库设计 四.主要功能 1. 编写注解 2. 业务类型枚举 3. 编写切片 4. ip工具类 5. 事件发布 6. 监听者 五.测试 1. controller 2. service 3. dao 4. 测试 5. 数据库 六.总结 一.前言 我们在企业级的开发中,必不可少的是对日志的记录,实现有很多种方式,常见的就是基于AOP+注解进行保存,同时考虑到程序的流畅和效率,我们可以使用异步进行保存! 二.基础环境 1. 导入

随机推荐