
pre:has(code) { filter: blur(10px) !important; padding: 1rem !important; }
PreAuthLoginEndpoint 预登录端点:
GET /login 请求。CryptoService.readPublicKey() 读取 RSA 公钥。AuthProviderService 查询启用的登录方式(本地表单、社交登录等)。/login 页面是我们能看到的唯一“官方视角”,公钥、CSRF、登录方式等信息都在这里以 HTML/JS 的形式暴露出来。CryptoService(接口) / RsaKeyService(实现)
readPublicKey():给 PreAuthLoginEndpoint 用,把公钥塞到前端页面。decrypt(byte[]):给登录链路用,解密前端传来的密文密码。对前端的意义:
如果站点启用了“前端加密 + 后端解密”的模式,我们必须用与后端一致的公钥和算法才能登录成功。
AuthProviderService
/login 页面中以按钮、链接的形式体现。LoginSecurityConfigurer + AuthenticationWebFilter
AuthenticationWebFilter。POST /login 请求,进入认证流程。fetch('/login'),最终都会走到这个过滤器链上。LoginAuthenticationConverter
username;password(明文或密文);_csrf 等字段。CryptoService.decrypt() 把密文解密成明文密码;对前端的意义:
决定了“密码字段到底是明文还是密文”这件事怎么处理——只要我们按照它接受的格式提交,就不需要改任何后端代码。
DefaultUserDetailService / UserService / RoleService
HaloUserDetails,支持标记是否启用 2FA。UsernamePasswordHandler
RememberMeRequestCache 等组件做“记住我”之类的增强。fetch('/login') 最终会得到 JSON 还是重定向,直接影响弹窗里怎么展示结果。
1.2 模块关系图flowchart TD B[Browser 前端] -->|GET /login 登录页| P[PreAuthLoginEndpoint 预登录端点] B -->|POST /login 提交表单或 fetch| F[AuthenticationWebFilter 表单登录过滤器] P --> C[CryptoService / RsaKeyService] P --> APS[AuthProviderService 登录方式服务] P --> GI[GlobalInfoService 全局站点信息] P --> T[Thymeleaf 模板 login.html] F --> LAC[LoginAuthenticationConverter 表单转换器] LAC --> C F --> AM[ReactiveAuthenticationManager 认证管理器] AM --> UDS[DefaultUserDetailService 用户明细服务] UDS --> USvc[UserService 用户查询] UDS --> RSvc[RoleService 角色查询] F --> H[UsernamePasswordHandler 成功/失败处理器] H --> RM[RememberMeRequestCache 记住我]
/login 页面:
publicKey 变量_csrf、可选的社交登录按钮等。POST /login:
LoginAuthenticationConverter 的预期;这意味着:
只要我们在前端构造出一份“看起来像
/login表单提交”的请求,就可以无侵入地接入整条登录链路。
提供一个截图:
我已经实现了 弹窗登录功能 有需要的可以找我要,暂时不打算全部公开不知道会不会有什么BUG
效果视频: