前言
大家好,我是雪荷。在项目中有些功能需要用户先登录才可使用,我们不妨设置一个全局登录拦截器,强制用户登录,达到先登录再使用的效果。
思路
思路并不复杂,就是在执行每个Controller方法前执行getLoginUser方法判断登录用户是否是否为空,如果为空返回40100状态码,前端axios根据状态码跳转至登录页。因为在执行每个方法前都要执行getLoginUser方法(登录和注册接口除外),那么通过AOP实现是再方便不过了,并且强制用户在使用每个功能前要先登录。
代码实现
LoginInterceptor(登录拦截器):
/**
* 登录拦截 AOP
*/
@Aspect
@Component
public class LoginInterceptor {
@Resource
private UserService userService;
@Before("execution(* com.hjj.homieMatching.controller.*.*(..)) && " +
"!execution(* com.hjj.homieMatching.controller.UserController.userLogin(..)) && " +
"!execution(* com.hjj.homieMatching.controller.UserController.userRegister(..))")
public void beforeControllerMethodExecution() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();
if (userService.getLoginUser(request) == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN);
}
}
}
BusinessException:
public class BusinessException extends RuntimeException{
private final int code;
private final String description;
public BusinessException(String message, int code, String description) {
super(message);
this.code = code;
this.description = description;
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code= errorCode.getCode();
this.description= errorCode.getDescription();
}
public BusinessException(ErrorCode errorCode, String description) {
super(errorCode.getMessage());
this.code= errorCode.getCode();
this.description= description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
ErrorCode:
public enum ErrorCode {
SUCCESS(0,"ok",""),
PARAMS_ERROR(40000,"请求参数错误",""),
NULL_ERROR(40001,"请求数据为空",""),
NOT_LOGIN(40100,"未登录",""),
NO_AUTH(40101,"无权限",""),
FORBIDDEN(40301,"禁止操作",""),
TOO_MANY_REQUEST(42900, "请求过于频繁", ""),
SYSTEM_ERROR(50000,"系统内部异常","");
/**
* 状态码
*/
private final int code;
/**
* 状态码信息
*/
private final String message;
/**
* 状态码描述
*/
private final String description;
ErrorCode(int code, String message, String description) {
this.code = code;
this.message = message;
this.description = description;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
}
注意: 声明登录接口和注册接口不用执行beforeControllerMethodExecution方法。
getLoginUser(获取登录用户):
public User getLoginUser(HttpServletRequest request){
if(request == null) {
return null;
}
Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
if(userObj == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN);
}
return (User) userObj;
}
前端myAxios.ts文件:
import axios from 'axios';
const isDev = process.env.NODE_ENV === 'development';
const myAxios = axios.create({
baseURL: isDev ? 'http://localhost:8080/api' : '线上地址',
})
myAxios.defaults.withCredentials = true; //设置为true
myAxios.interceptors.request.use(function (config) {
console.log('我要发请求啦');
return config;
}, function (error) {
return Promise.reject(error);
});
myAxios.interceptors.response.use(function (response) {
console.log('我收到你的响应啦');
console.log(response?.data.code);
// 未登录则跳转登录页
if (response?.data?.code === 40100) {
const redirectUrl = window.location.href;
window.location.href = `/user/login?=redirect=${redirectUrl}`;
}
return response.data;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
export default myAxios;
测试:
启动前后端项目,发现无论点击任一 Tab 栏都会跳转登录页强制登录,至此全局登录拦截已实现。欢迎大佬们分享更好的实现方法。
编辑
前端代码没什么变化,主要添加一个LoginInterceptor就好了。
开源项目
厚米匹配
网址:厚米匹配系统
灵犀 BI
网址:鱼智能 BI