在项目中,不进行登录验证也可直接进行主页面的访问;
在过滤器、拦截器中拦截前端发起的请求,判断用户是否已经完成登录;登陆了就放行,如果没有登录则返回提示信息,跳转到登录页面。
过滤器具体的处理逻辑如下:
获取本次请求的URI
判断本次请求, 是否需要登录, 才可以访问(如果是拦截器,不需要该步骤)
如果不需要,则直接放行
判断登录状态,如果已登录,则直接放行
如果未登录, 则返回未登录结果
在yml文件中存入放行路径
excludePath: '/employee/login,/employee/logout,/backend/**,/front/**,favicon.ico'
过滤器
import com.alibaba.fastjson.JSON;
import com.itheima.reggie.utils.common.BaseContext;
import com.itheima.reggie.utils.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Arrays;
/**
* 登录校验
*/
@WebFilter("/*") // 表示该类是一个filter,拦截所有请求
@Slf4j
public class LoginCheckFilter implements Filter {
// 2.2 创建路径匹配器对象
AntPathMatcher apm = new AntPathMatcher();
@Value("${excludePath}")
String excludePath;
/**
* 判断是否登录,并确定是否放行
*
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
//1. 获取本次请求的URI
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String requestURI = req.getRequestURI();
//2. 判断本次请求, 是否需要登录, 才可以访问
// 2.1 解析要放行的所有请求
String[] urls = excludePath.split(",");
// 2.3 检查是否在放行范围
if (checkUrl(urls, requestURI)) {
//3. 如果不需要,则直接放行
filterChain.doFilter(request, response);
return; // 后面代码不需要执行,直接结束
}
//4. 判断登录状态,如果已登录,则直接放行
HttpSession session = req.getSession();
Long employeeId = (Long) session.getAttribute("employee");
if (employeeId != null) {
long id = Thread.currentThread().getId();
log.info("线程id为:{}",id);
//已经登录,将id存入线程工具类中
BaseContext.setCurrentId(employeeId);
// 放行
filterChain.doFilter(request, response);
return; // 后面代码不需要执行,直接结束
}
//5. 如果未登录, 则返回未登录结果
// 前端页面写死的,只识别NOTLOGIN;接受到该符号后,跳转到登录页面
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
}
/**
* 判断某个请求是否在不登录的时候就可以放行
*
* @param urls
* @param requestURI
* @return
*/
private boolean checkUrl(String[] urls, String requestURI) {
boolean matchResult = false;
for (String url : urls) {
// 匹配 本次请求的requestURI 是否符合 url
matchResult = apm.match(url, requestURI);
if (matchResult) {
return true;
}
}
log.info("本次请求url为:{},是否需要放行:{}", requestURI, matchResult);
return false;
}
}
需要在引导类上, 加上Servlet组件扫描的注解, 来扫描过滤器配置的@WebFilter注解, 扫描上之后, 过滤器在运行时就生效了。
@Slf4j
@SpringBootApplication
@ServletComponentScan
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class,args);
log.info("项目启动成功...");
}
}
@ServletComponentScan 的作用:
在SpringBoot项目中, 在引导类/配置类上加了该注解后, 会自动扫描项目中(当前包及其子包下)的
@WebServlet ,
@WebFilter ,
@WebListener 注解, 自动注册Servlet的相关组件 ;
拦截器具体的处理逻辑如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.reggie.utils.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 员工登录拦截器
*/
@Slf4j
@Component
public class EmployeeInterceptor implements HandlerInterceptor {
/**
* 重写preHandle方法,校验登录状态,如果已经登录,则放行;否则跳转到登录页面
*
* @param request 请求对象
* @param response 响应对象
* @param handler 处理器封装对象
* @return
* @throws Exception 1. 获取本次请求的URI
* 2. 判断登录状态,如果已登录,则直接放行
* 3. 如果未登录, 则返回未登录结果
* 4. 把拦截器配置进容器,并指定拦截规则
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 获取本次请求的URI
String requestURI = request.getRequestURI();
// 2. 放行不需要拦截的资源 /employee/login
/* if ("/employee/login".equals(requestURI)) {
return true;
} */
log.info("本次请求URI:{}", requestURI);
Long employeeId = (Long) request.getSession().getAttribute("employee");
// 3. 如果未登录, 则返回未登录结果
if (employeeId == null) {
// 前端跳转到登录页面,需要用到用到一个特殊标识:NOTLOGIN
// 因为preHandle返回值类型为boolean,所以不能return RObj
// 使用response原生API
// 创建R对象,并且手动序列化为JSON格式字符串
/**
* writeValueAsString(obj) 把obj序列化为JSON格式字符串
* writeValue(writer, obj) 把obj序列化为JSON格式字符串,然后写入writer
*/
new ObjectMapper().writeValue(response.getWriter(), R.error("NOTLOGIN"));
// 拦截
return false;
}
// 4. 判断登录状态,如果已登录,则直接放行
// 放行
return true;
// 5. 把拦截器配置进容器,并指定拦截规则
}
}
在配置文件写入要排除的路径
excludePath: '/employee/login,/employee/logout,/backend/**,/front/**,/employee/login,favicon.ico'
web初始化配置配置要拦截的路径
import com.itheima.reggie.web.interceptor.EmployeeInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.Arrays;
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Autowired
EmployeeInterceptor employeeInterceptor;
@Value("${excludePath}")
String excludePath;
/**
* 配置拦截器,并映射拦截路径
*
* @param registry
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始加载拦截器...");
String[] urls = excludePath.split(",");
log.info("直接放行的路径是:{}", Arrays.toString(urls));
registry
.addInterceptor(employeeInterceptor)
// 本拦截器拦截的资源路径
.addPathPatterns("/employee/**")
// 本拦截器不拦截的资源路径
// .excludePathPatterns("/employee/login");
.excludePathPatterns(urls);
}
}