基于Spring框架实现自定义登录验证CheckAuth注解,此注解主要用于类和方法上,实现接口调用时进行用户认证校验,注解代码如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.TYPE })
public @interface CheckAuth {
String value() default "";
String describe() default "";
}
自定义拦截器代码如下
import java.lang.annotation.Annotation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
public class AuthAnnotationInterceptor implements HandlerInterceptor {
@Autowired
AdminUtilsService adminUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
CheckAuth CheckAuthAnnotation = findAnnotation(handler, CheckAuth.class);
if (CheckAuthAnnotation != null && adminUtils != null) {
boolean bLogin = adminUtils.isAuthenticated(); // 判断是否登录
if (!bLogin) {
response.reset();
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setCharacterEncoding("UTF-8");
response.getWriter().write("Authentication required, Access denied.");
response.flushBuffer();
return false;
}
return true;
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
private <T extends Annotation> T findAnnotation(Object handler, Class<T> annotationClass) {
if (handler instanceof HandlerMethod) {
T annotation = null;
HandlerMethod handlerMethod = (HandlerMethod) handler;
annotation = handlerMethod.getMethodAnnotation(annotationClass); // 此代码只能获取作用于方法上的注解
if (annotation == null) {
// 注解用于类上时,必须通过AnnotationUtils来获取类上的注解
annotation = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), annotationClass);
}
return annotation;
} else {
return AnnotationUtils.findAnnotation(ClassUtils.getUserClass(handler), annotationClass);
}
}
}
本人使用的shiro权限框架,为了模块解耦,随意组合,避免注解模块依赖于shiro,特地定义了AdminUtilsService来实现解耦,使之整合到其他项目时,只要实现AdminUtilsService接口就可以。
其中adminUtils.isAuthenticated()方法代码如下所示:
public boolean isAuthenticated() {
// 很多时候基于token或session里面的值来判断是否登录的,shiro是通过如下代码来判断的。
return SecurityUtils.getSubject().isAuthenticated();
}
特别要注意的,获取注解时,网上很多代码获取直接都只实现了如下代码
if (handler instanceof HandlerMethod) {
CheckAuth annotation = null;
HandlerMethod handlerMethod = (HandlerMethod) handler;
annotation = handlerMethod.getMethodAnnotation(CheckAuth.class);
省略。。。。
}
这样判断只能获取方法上面的注解
上面代码用户
public class DemoController {
@CheckAuth
public Result getList() {
// 代码省略
}
}
假如注解作用于类上,即@Target(value={ElementType.TYPE},获取注解就不能用handlerMethod.getMethodAnnotation(CheckAuth.class);来获取了,幸运的是Spring本身自带了一个获取的注解工具类AnnotationUtils.findAnnotation,可以获取类上的注解。通过AnnotationUtils.findAnnotation来查找注解后,我们就不需要每个接口方法都添加@CheckAuth注解,使用方法如下:
@CheckAuth
public class DemoController {
public Result getList() {
// 代码省略
}
public Result getUser() {
// 代码省略
}
}