文章目录
- 概要
- 整体流程
- 注意事项
- 一、拦截路径
- 二、token
- 三、注册防止用户重复提交
- 苍穹外卖登录退出分析
- 注意
- 解决JWT退出后依然有效的问题
概要
结合Spring Boot和Vue3实现安全的用户登录
和退出
功能,并使用拦截器、JWT和Redis缓存来提高系统的安全性和性能。
整体流程
注意事项
一、拦截路径
像登录页面的路径就不要拦截了,否则都不能登录了
例如:
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
private JwtTokenapiInterceptor jwtTokenapiInterceptor;
/**
* 注册自定义拦截器
*/
protected void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器
// 添加拦截路径 排除拦截路径
registry.addInterceptor(jwtTokenapiInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/employee/login"); // 不拦截登录的接口
}
}
二、token
- 用户登录验证密码等通过后,生成token,token中可存用户id,并存入redis(将token存储到redis中,便于管理token的状态和生命周期)。
- 下次请求拦截器先拦截,解析token中的用户id,然后从redis里面读取token验证,验证用户合法性。
- 退出登录,前端发一个请求给后端,删除redis中的token。
注意:
- 不要将敏感信息(如密码)放在token中。
- 妥善保管用于生成和验证token的密钥。
三、注册防止用户重复提交
我自己写了一个小demo,邮箱注册登录。
发送验证码,可能不小心点了两下等重复提交操作。解决方法:用redis
其他方法:
记录发送时间戳
:后端可以记录每个用户发送验证码的时间戳。如果用户在短时间内发送多次验证码请求,后端可以检查最新的请求时间戳与上次请求时间戳的间隔,如果间隔时间太短,就拒绝处理额外的请求
前端限制
:在前端实现点击发送验证码按钮后,禁用按钮一段时间,防止用户连续点击发送。可以在发送验证码后,将按钮禁用一段时间,以防止用户误操作多次点击发送。
苍穹外卖登录退出分析
定义拦截器:
注册拦截器:
用户登录:
用户提交登录请求➡️后端认证用户(拦截器会放行登录接口,先判断用户名密码,然后生成token)➡️生成令牌token,并将其返回给客户端
@PostMapping("/login")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
log.info("员工登录:{}", employeeLoginDTO);
Employee employee = employeeService.login(employeeLoginDTO);
// 登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
// token中存入用户id
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token)
.build();
return Result.success(employeeLoginVO);
}
用户退出:
@PostMapping("/logout")
public Result<String> logout() {
return Result.success();
}
看看前端代码:
登录成功之后会把token存入本地cookie。
之后的请求,会使用axios的拦截器
为每个请求的headers添加一个token,后端拦截器
根据此token用于身份验证。
// 部分代码
if (UserModule.token) {
config.headers['token'] = UserModule.token
} else if (UserModule.token && config.url != '/login') {
window.location.href = '/login'
return false
}
注意
如果苍穹的 Token 仅依靠 JWT 进行验证,而不通过 Redis 校验,那么退出实际上是伪退出
。你可以复制退出前的 Token,退出登录后再将其粘贴到请求头中,依然可以继续使用。前端发起退出操作请求,清除本地Cookie存储的 Token,后端接收到请求后直接返回成功
。让登录失效的关键在于前端,而不是后端。JWT 的过期时间在生成时就已经确定,后端无法动态更改。因此,Token 本身并没有立即失效,退出只是前端移除它了,Token 依然有效。
解决JWT退出后依然有效的问题
- 将Token存储到
Redis
中并进行验证。在每次请求时校验Redis中的Token是否有效。当用户退出时,从Redis中删除该Token - 使用双Token机制(Access Token + Refresh Token)
❤觉得有用的可以留个关注ya~❤