若依版本v3.9.2 前后端分离版本参考流程时序图登录流程前端页面先获取验证码base64和验证码key返回给前端前端根据base64渲染出验证码验证码结果与key放入redis然后调用登录接口根据用户名密码验证码(key以及用户输入的结果)进行校验代码定义在SysLoginController:在LoginService中会进行参数校验如验证码校验用户名与密码是否符合规则等然后进行用户名密码比对比对成功创建token并返回给前端用于后续接口的登录校验public String login(String username, String password, String code, String uuid) { // 验证码校验 validateCaptcha(username, code, uuid); // 登录前置校验 loginPreCheck(username, password); // 用户验证 Authentication authentication null; try { UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(username, password); AuthenticationContextHolder.setContext(authenticationToken); // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername authentication authenticationManager.authenticate(authenticationToken); } catch (Exception e) { if (e instanceof BadCredentialsException) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(user.password.not.match))); throw new UserPasswordNotMatchException(); } else { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); throw new ServiceException(e.getMessage()); } } finally { AuthenticationContextHolder.clearContext(); } AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message(user.login.success))); LoginUser loginUser (LoginUser) authentication.getPrincipal(); recordLoginInfo(loginUser.getUserId()); // 生成token return tokenService.createToken(loginUser); }创建token的同时会将登录凭证(token)与用户信息存入redis并设置过期时间进入首页由于前面登录成功获取到了token, 前端会将token存入cookie用于后续接口调用的登录校验在首页会调用/getInfo和/getRouters接口获取用户信息和路由信息这两个接口都需要登录校验这两次请求都会被JwtAuthenticationTokenFilter拦截在这个过滤器中会进行token校验校验成功会将用户信息放入SpringSecurity上下文在获取路由信息时会从SpringSecurity获取用户信息如果获取失败会报错并返回401之后根据用户的角色权限返回给前端对应的路由信息继续访问首页退出登录流程前端调用/logout接口会进行LogoutSuccessHandlerImpl会根据token找到用户信息并在redis中删除对应登录凭证记录用户退出登录日志返回前端响应退出登录成功前端知道退出登录成功之后删除存储在pinia中的用户信息后续请求接口不会携带token