在访问网站时,常常需要进行权限校验,从而决定用户是否能够正常访问。可以使用过滤器或拦截器加session来实现。本文使用HandlerInterceptor拦截器实现登录校验。
创建拦截器
创建拦截器的基本流程:
1. 创建一个拦截器类实现HandlerInterceptor接口,重写其preHandle方法
(拦截作用主要由preHandle实现)
2. 在配置类中对该拦截器进行配置
(哪些地址拦截,哪些地址不拦截)
1. 生成拦截器类
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("拦截到请求:{}", request.getRequestURI() + " 拦截器" + this.getClass().getSimpleName());
HttpSession session = request.getSession();
// 如果是来自后台的请求 (请求地址包含 employee,来自EmployeeController)
if (request.getRequestURI().contains("employee")){
boolean isHave = !(session.getAttribute("employeeInfo") == null);
if (!isHave) {
log.info("用户未登录");
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
}
return isHave;
// 如果是来自客户端的请求 (请求地址包含 user,来自UserController)
} else if (request.getRequestURI().contains("user")) {
Object userInfom = request.getSession().getAttribute("userInfo");
boolean isHave = !(userInfom == null);
if (!isHave) {
log.info("用户未登录");
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
}
return isHave;
}
return false;
}
}
preHandle方法返回true表示放行,false不放行
2. 配置拦截器
@Slf4j
@Configuration
public class WebMVCConfig extends WebMvcConfigurationSupport {
@Autowired
private MyInterceptor myInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns 用于添加拦截规则
// excludePathPatterns 排除拦截
registry.addInterceptor(myInterceptor).addPathPatterns("/**").
excludePathPatterns("/employee/login", "/employee/logout", "/backend/**", "/front/**", "/user/login");
}
}
其中,backend和front里面放的是一些静态资源,网页和图片等,它们被解除了拦截。静态资源本身不需要被拦截,真正要拦截的是针对controller的请求,如http://xxx:8080/employee/list。拦截了针对controller的请求,即使静态资源能访问也没有关系,无法通过请求拿到数据。
这个WebMVCConfig类专门进行web相关的一些配置,比如路径映射配置等。
编写Controller层
现在拦截器已经配置好了,开始进行controller层的编写(login和logout)
其中login的主要逻辑为
根据请求封装的用户对象,按其属性值为条件(这里主要是username和password),进行查询
if (没查到) {
返回R对象(失败信息);
} else (查到) {
session保存用户信息;
返回R对象(用户对象);
}
logout主要就是对session中的数据进行清除
下面是controller代码
@Slf4j
@RequestMapping("/employee")
@RestController
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public R<Employee> login(@RequestBody Employee employee, HttpSession session){
// 对密码加密处理
String password = DigestUtils.md5DigestAsHex(employee.getPassword().getBytes());
// 查询条件:根据输入的username和password查询,且status为1
LambdaQueryWrapper<Employee> employeeLambdaQueryWrapper = new LambdaQueryWrapper<>();
employeeLambdaQueryWrapper.like(employee.getUsername() != null, Employee::getUsername, employee.getUsername());
employeeLambdaQueryWrapper.like(employee.getPassword() != null, Employee::getPassword, password);
employeeLambdaQueryWrapper.eq(Employee::getStatus, 1);
Employee employeeQuery = employeeService.getOne(employeeLambdaQueryWrapper);
if (employeeQuery == null) {
return R.error("登陆失败");
}
// 向session保存数据,供拦截器检查
session.setAttribute("employeeInfo", employeeQuery.getUsername());
return R.success(employeeQuery);
}
@PostMapping("/logout")
public R logout(HttpSession session){
// 清除 Session
session.removeAttribute("employeeInfo");
return R.success("退出成功");
}
这里拦截器进行拦截跳转回登录界面、登录后跳转到系统首页,均由前端实现。
登录成功进入首页:
methods: {
async handleLogin() {
this.$refs.loginForm.validate(async (valid) => {
if (valid) {
this.loading = true
let res = await loginApi(this.loginForm)
if (String(res.code) === '1') {
localStorage.setItem('userInfo',JSON.stringify(res.data))
window.location.href= '/backend/index.html'
} else {
this.$message.error(res.msg)
this.loading = false
}
}
})
}
}
拦截返回登录界面:
service.interceptors.response.use(res => {
if (res.data.code === 0 && res.data.msg === 'NOTLOGIN') {// 返回登录页面 NOTLOGIN
console.log('---/backend/page/login/login.html---')
localStorage.removeItem('userInfo')
window.top.location.href = '/backend/page/login/login.html'
} else {
return res.data
}
},
如此,便实现了SpringBoot项目利用拦截器进行登录校验。