SpringBoot使用自定义注解实现权限拦截的示例
本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下:
HandlerInterceptor(处理器拦截器)
常见使用场景
- 日志记录:记录请求信息的日志,以便进行信息监控,信息统计,计算PV(pageView)等
- 性能监控:
- 权限检查:
- 通用行为:
使用自定义注解实现权限拦截
首先HandlerInterceptor了解
在HandlerInterceptor中有三个方法:
publicinterfaceHandlerInterceptor{
//在执行目标方法之前执行
booleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException;
//执行目标方法之后执行
voidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException;
//在请求已经返回之后执行
voidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException;
}
在以上注释中已经写明执行顺序,测试及测试结果如下:
publicclassTestInterceptorimplementsHandlerInterceptor{
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
System.out.println("preHandler");
returntrue;
}
@Override
publicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{
System.out.println("postHandler");
}
@Override
publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{
System.out.println("afterCompletion");
}
}
结果:
preHandler
postHandler
afterCompletion
如何配置拦截器后面讲:
下面来讲讲这个拦截器是拦截的什么?
方法拦截器HandlerInterceptor
我们使用SpringMVC都知道SpringMVC是基于方法的请求处理,和Struts2有明显区别(我是这么理解的),并且Controller是单例模式,所有请求都是从DispatcherServlet来调用请求url对应的方法的(处理器映射器的功能),那么它是一个方法拦截器,如何知道呢?
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
System.out.println(handler.getClass());
returntrue;
}
执行结果:
classorg.springframework.web.method.HandlerMethod
已经看到拦截器如何工作,并且知道它是方法级别的拦截器,那么接下来看看如何配置拦截器,让它在服务器运行期间起作用
实现HandlerInterceptor
实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类
HandlerInterceptorAdapter适配器是对HandlerInterceptor接口做了默认实现,这种适配器模式,是为了方便开发者只去想要复写方法,其他方法采取默认措施.
上面的TestInterceptor就是一个Demo,具体可以按需求在我们想要拦截的位置进行相应的逻辑处理
配置拦截器
从Spring4.x开始,就支持注解配置具体是使用@Configuration注解标注一个普通类,使该类成为配置类,可以在该类中定义Bean,以及注入一些配置参数等.
首先,我们要配置拦截器,就需要想SpringMvc的拦截链中取注入我们的拦截器,这样才能请求进来时去拦截我们想要拦截的请求,所以,需要我们新建一个普通类,使用@Configuration注解标注在类名上,并且让该类继承WebMvcConfigurerAdapter,为什么不实现WebMvcConfigurer接口呢?因为方法太多,我们不需要复写其中所有方法...
下面让我们新建一个配置类,来配置我们的拦截器
@Configuration
publicclassInterceptorConfigextendsWebMvcConfigurerAdapter{
publicvoidaddInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(newTestInterceptor()).addPathPatterns("/**");
}
}
复写addInterceptors之后,当我们的服务器启动时,会自动调用这个方法,参数怎么传我们都不用管(目前是java初级阶段,没空研究Spring深层原理),我们只要知道这个方法一定会被调用就行了.
我们直接new一个自定义拦截器,注册到整个拦截链中,并且制定拦截路径,这样当满足请求url拦截配置时,我们的自定义拦截器就会执行相应的方法了.
拦截方法是非常灵的,除了拦截配置的,也可以拦截非匹配的,也可以根据正则表达式拦截请求
至此,我们的拦截器就完成了,接下来自定义权限相关注解
自定义权限注解
定义一个@interface类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interfaceAccess{
String[]value()default{};
String[]authorities()default{};
String[]roles()default{};
}
@Target注解是标注这个类它可以标注的位置:
常用的元素类型(ElementType):
publicenumElementType{
/**Class,interface(includingannotationtype),orenumdeclaration*/
//TYPE类型可以声明在类上或枚举上或者是注解上
TYPE,
/**Fielddeclaration(includesenumconstants)*/
//FIELD声明在字段上
FIELD,
/**Methoddeclaration*/
//声明在方法上
METHOD,
/**Formalparameterdeclaration*/
//声明在形参列表中
PARAMETER,
/**Constructordeclaration*/
//声明在构造方法上
CONSTRUCTOR,
/**Localvariabledeclaration*/
//声明在局部变量上
LOCAL_VARIABLE,
/**Annotationtypedeclaration*/
ANNOTATION_TYPE,
/**Packagedeclaration*/
PACKAGE,
/**
*Typeparameterdeclaration
*
*@since1.8
*/
TYPE_PARAMETER,
/**
*Useofatype
*
*@since1.8
*/
TYPE_USE
}
@Retention注解表示的是本注解(标注这个注解的注解保留时期)
publicenumRetentionPolicy{
/**
*Annotationsaretobediscardedbythecompiler.
*/
//源代码时期
SOURCE,
/**
*Annotationsaretoberecordedintheclassfilebythecompiler
*butneednotberetainedbytheVMatruntime.Thisisthedefault
*behavior.
*/
//字节码时期,编译之后
CLASS,
/**
*Annotationsaretoberecordedintheclassfilebythecompilerand
*retainedbytheVMatruntime,sotheymaybereadreflectively.
*
*@seejava.lang.reflect.AnnotatedElement
*/
//运行时期,也就是一直保留,通常也都用这个
RUNTIME
}
@Documented是否生成文档的标注,也就是生成接口文档是,是否生成注解文档
注解说完了,下面需要到对应的controller的方法中取添加注解,配置该方法允许的权限
在方法上配置权限
@RestController
publicclassHelloController{
@RequestMapping(value="/admin",produces=MediaType.APPLICATION_JSON_UTF8_VALUE,method=RequestMethod.GET)
//配置注解权限,允许身份为admin,或者说允许权限为admin的人访问
@Access(authorities={"admin"})
publicStringhello(){
return"Hello,admin";
}
}
编写权限逻辑
//自定义一个权限拦截器,继承HandlerInterceptorAdapter类
publicclassAuthenticationInterceptorextendsHandlerInterceptorAdapter{
//在调用方法之前执行拦截
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
//将handler强转为HandlerMethod,前面已经证实这个handler就是HandlerMethod
HandlerMethodhandlerMethod=(HandlerMethod)handler;
//从方法处理器中获取出要调用的方法
Methodmethod=handlerMethod.getMethod();
//获取出方法上的Access注解
Accessaccess=method.getAnnotation(Access.class);
if(access==null){
//如果注解为null,说明不需要拦截,直接放过
returntrue;
}
if(access.authorities().length>0){
//如果权限配置不为空,则取出配置值
String[]authorities=access.authorities();
SetauthSet=newHashSet<>();
for(Stringauthority:authorities){
//将权限加入一个set集合中
authSet.add(authority);
}
//这里我为了方便是直接参数传入权限,在实际操作中应该是从参数中获取用户Id
//到数据库权限表中查询用户拥有的权限集合,与set集合中的权限进行对比完成权限校验
Stringrole=request.getParameter("role");
if(StringUtils.isNotBlank(role)){
if(authSet.contains(role)){
//校验通过返回true,否则拦截请求
returntrue;
}
}
}
//拦截之后应该返回公共结果,这里没做处理
returnfalse;
}
}
至此,我们启动服务器,访问接口,就能看到效果,这里不做示范了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。