springboot 实现登录拦截和权限拦截
拦截器的注册器
package lingnan.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
*
*/
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/user/toLogin").setViewName("login");
}
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new RequestLog()).addPathPatterns("/**");
// super.addInterceptors(registry);
// }
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
//下面是controller跳转登录界面的url,解除此拦截
.excludePathPatterns("/user/toLogin")
//下面这些是解除静态资源的拦截
.excludePathPatterns("/assets/**")
.excludePathPatterns("/css/**")
.excludePathPatterns("/fonts/**")
.excludePathPatterns("/images/**")
.excludePathPatterns("/js/**")
.excludePathPatterns("/layui/**")
.excludePathPatterns("/static/**");
super.addInterceptors(registry);
}
}
自定义拦截器
package lingnan.interceptor;
import lingnan.entity.User;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
@Component
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
System.out.println("afterCompletion----" + user + " ::: " + request.getRequestURL());
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
System.out.println("postHandle----" + user + " ::: " + request.getRequestURL());
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User) request.getSession().getAttribute("loginUser");
System.out.println("preHandle----" + user + " ::: " + request.getRequestURL());
//controller中跳转到登录界面的方法为login()如果是这个方法直接true
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取用户token
Method method = handlerMethod.getMethod();
System.out.println("method:::"+method.getName());
if(method.getName().equals("login"))
return true;
//如果loginUser为空说明未经过登录
if (user == null) {
request.setAttribute("loginError", "请先登录");
// 获取request返回页面到登录页
request.getRequestDispatcher("/user/toLogin").forward(request,response);
return false;
}
//用于拦截普通用户试图登录管理界面,我的管理界面url含有manage字符串
if(user.getAccess()==1&&request.getRequestURL().indexOf("manage")!=-1){
request.setAttribute("loginError", "无权限,不是管理员");
// 获取request返回页面到登录页
request.getRequestDispatcher("/user/toLogin").forward(request,response);
return false;
}
return true;
}
}
题外:
用Aop切面编程,可以看到各个方法的输入输出值等等
package lingnan.log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.omg.PortableInterceptor.RequestInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* Created by pd on 17/12/07.
*/
//描述切面类
@Aspect //@Aspect注解就是告诉spring 这是一个aop类,AOP切面
@Configuration //可理解为用spring的时候xml里面的<beans>标签,类中 @Bean可以理解为用Spring的时候xml里面的<bean>标签
public class LogRecordAspect {
private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);
// 用@Pointcut来注解一个切入方法
//@Pointcut注解 声明这是一个需要拦截的切面,也就是说,当调用任何一个controller方法的时候,都会激活这个aop
@Pointcut("execution(* lingnan.controller.*Controller.*(..))") //两个..代表所有子目录,最后括号里的两个..代表所有参数
public void excudeService() {
}
//@Around注解 环绕执行,就是在调用之前和调用之后,都会执行一定的逻辑
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String url = request.getRequestURL().toString();
String method = request.getMethod();
String uri = request.getRequestURI();
String queryString = request.getQueryString();
try{
Object[] args =pjp.getArgs();
for(int i=0;i<args.length;i++){
if(args[i] instanceof RequestInfo){
RequestInfo r= (RequestInfo) args[i];
logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, r.toString());
}else{
logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri,args[i]);
}
}
}catch (Exception e){
logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri,queryString);
}
// result的值就是被拦截方法的返回值
Object result = pjp.proceed();
//logger.info("请求结束,controller的返回值是 " + result.toString());
//logger.info("请求结束,controller的返回值是 " + result);
return result;
}
}
另一种拦截器的事务记录,记录方法消耗时间,跟上面的LoginHandlerInterceptor 拦截器一样要注册到注册器上
package lingnan.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.Instant;
/*
HandlerInterceptoer拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适,
比如需要统计请求这个地址的响应时间
*/
/* Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截。
但是它适合更粗粒度的拦截,在请求前后做一些编解码处理、日志记录等。
*/
//用于参考没用上
public class RequestLog extends HandlerInterceptorAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestLog.class);
/**
* 前置检查,方法执行前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String ip = request.getRemoteAddr();
Instant startTime = Instant.now();
request.setAttribute("logrequestStartTime", startTime);
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取用户token
Method method = handlerMethod.getMethod();
LOGGER.info("用户:"+ip+",访问目标:"+method.getDeclaringClass().getName() + "." + method.getName());
LOGGER.info("params:"+request.getQueryString());
return true;
}
/**
* 方法执行中
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
// controller处理完成
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
Instant startTime = (Instant) request.getAttribute("logrequestStartTime");
Instant endTime = Instant.now();
long executeTime = endTime.toEpochMilli()- startTime.toEpochMilli();
// log it
if (executeTime > 1000) {
LOGGER.info("[" + method.getDeclaringClass().getName() + "." + method.getName() + "] 执行耗时 : "
+ executeTime + "ms");
} else {
LOGGER.info("[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "] 执行耗时 : "
+ executeTime + "ms");
}
}
}