SpringBoot使用自定义注解实现权限拦截的示例
本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下: HandlerInterceptor(处理器拦截器) 常见使用场景
使用自定义注解实现权限拦截 首先HandlerInterceptor了解 在HandlerInterceptor中有三个方法: public interface HandlerInterceptor { // 在执行目标方法之前执行 boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throws Exception; // 执行目标方法之后执行 void postHandle(HttpServletRequest request,Object handler,ModelAndView modelAndView)throws Exception; // 在请求已经返回之后执行 void afterCompletion(HttpServletRequest request,Exception ex)throws Exception; } 在以上注释中已经写明执行顺序,测试及测试结果如下: public class TestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request,Object handler) throws Exception { System.out.println("preHandler"); return true; } @Override public void postHandle(HttpServletRequest request,ModelAndView modelAndView) throws Exception { System.out.println("postHandler"); } @Override public void afterCompletion(HttpServletRequest request,Exception ex) throws Exception { System.out.println("afterCompletion"); } } 结果: preHandler 如何配置拦截器后面讲: 下面来讲讲这个拦截器是拦截的什么? 方法拦截器HandlerInterceptor 我们使用SpringMVC都知道SpringMVC是基于方法的请求处理,和Struts2有明显区别(我是这么理解的),并且Controller是单例模式,所有请求都是从DispatcherServlet来调用请求url对应的方法的(处理器映射器的功能),那么它是一个方法拦截器,如何知道呢? @Override public boolean preHandle(HttpServletRequest request,Object handler) throws Exception { System.out.println(handler.getClass()); return true; } 执行结果: class org.springframework.web.method.HandlerMethod 已经看到拦截器如何工作,并且知道它是方法级别的拦截器,那么接下来看看如何配置拦截器,让它在服务器运行期间起作用 实现HandlerInterceptor 实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类 上面的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,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; } } 至此,我们启动服务器,访问接口,就能看到效果,这里不做示范了 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |