
Sa-Token OAuth2 定制登录页与授权确认页重写 notLoginView / doLogin / doConfirm 策略实战【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token本篇以 Sa-Token 官方文档中的 OAuth2 定制化登录页面章节为主体系统讲解如何在 OAuth-Server 认证中心自定义「未登录视图」「登录接口」「授权确认视图」三个环节。阅读完成后你将掌握SaOAuth2Strategy.instance.notLoginView、doLoginHandle、confirmView三个策略的重写方式理解/oauth2/doLogin、/oauth2/doConfirm两个内置接口的参数契约并能结合SaOAuth2ServerProcessor源码确认每个策略的精确触发时机。一、先看懂默认行为authorize 路由何时弹出登录页与授权页Sa-Token OAuth2 模块将所有/oauth2/*请求统一分发到 SaOAuth2ServerProcessor 的dister()方法其中/oauth2/authorize走authorize()分支。从源码结构看authorize()的执行链条为校验response_type授权码式 / 隐藏式是否开启通过SaOAuth2Manager.getStpLogic().getLoginIdDefaultNull()判断当前会话是否已登录——未登录则直接返回SaOAuth2Strategy.instance.notLoginView.get()即弹出登录视图构建RequestAuthModel执行开发者自定义的授权前置检查userAuthorizeClientCheck校验重定向域名合法性与 Scope 签约情况若本次申请的 Scope 用户尚未授权isNeedCarefulConfirm为 true且客户端未开启isAutoConfirm则返回SaOAuth2Strategy.instance.confirmView.apply(clientId, scopes)即弹出授权确认视图见 SaOAuth2ServerProcessor.java#L124-L149校验全部通过且无需确认时直接生成 code 或 token 并重定向到客户端redirect_uri。两个内置接口的路由地址定义在 SaOAuth2Consts.java#L36-L37public static String doLogin /oauth2/doLogin; public static String doConfirm /oauth2/doConfirm;这三个策略字段的默认值不做任何定制时的行为在 SaOAuth2Strategy.java#L252-L264 中/** OAuth-Server端未登录时返回的View */ public SaOAuth2NotLoginViewFunction notLoginView () - 当前会话在 OAuth-Server 认证中心尚未登录; /** OAuth-Server端确认授权时返回的View */ public SaOAuth2ConfirmViewFunction confirmView (clientId, scopes) - 本次操作需要用户授权; /** OAuth-Server端登录函数 */ public SaOAuth2DoLoginHandleFunction doLoginHandle (name, pwd) - SaResult.error();也就是说默认实现只返回一句纯文本提示、登录恒失败。要落地一个真正可用的 OAuth2 认证中心 UI必须重写这三个策略。它们对应的函数式接口分别是SaOAuth2NotLoginViewFunctionSupplierObject无参数返回视图对象SaOAuth2ConfirmViewFunctionBiFunctionString, ListString, Object参数为clientId与scopes列表返回视图对象SaOAuth2DoLoginHandleFunctionBiFunctionString, String, Object参数为name、pwd返回登录结果。返回的“视图”对象并不限定为 Spring 的ModelAndView——只要是 Web 框架能处理的响应体即可例如字符串、视图对象或 JSON。二、自定义 OAuth-Server 端的登录视图notLoginView重写SaOAuth2Strategy.instance.notLoginView策略将未登录时的返回视图替换为自己的登录页Autowired public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) { // 配置未登录时返回的View SaOAuth2Strategy.instance.notLoginView () - { return new ModelAndView(xxx.html); }; }上面的Autowired方法签名用于在 Spring 容器中将SaOAuth2ServerConfig注入进来同时借这个时机完成策略定制策略本身与容器无关也可以在任意初始化阶段直接赋值。登录页如何完成登录调用 /oauth2/doLogin在返回的登录视图中通过 ajax 方式调用/oauth2/doLogin接口。该接口接受的参数如下参数是否必填说明name否账号pwd否密码接口内部实现见 SaOAuth2ServerProcessor.java#L229-L232public Object doLogin() { SaRequest req SaHolder.getRequest(); return SaOAuth2Strategy.instance.doLoginHandle.apply(req.getParam(Param.name), req.getParam(Param.pwd)); }可以看到它只提取name和pwd两个参数然后原样委托给doLoginHandle策略——接口的返回值完全由你重写的doLoginHandle策略自由决定框架不做二次包装。官方 demo 认证端给出了完整示例登录成功后调用StpUtil.login()建立会话并顺带把 token 回传给前端// 登录处理函数 SaOAuth2Strategy.instance.doLoginHandle (name, pwd) - { if(sa.equals(name) 123456.equals(pwd)) { StpUtil.login(10001); return SaResult.ok().set(satoken, StpUtil.getTokenValue()); } return SaResult.error(账号名或密码错误); };示例取自 SaOAuth2ServerController.java#L33-L57三、自定义登录 API三种常见需求及对应方案针对「登录接口本身」的不同定制诉求文档按需求点给出了三套方案可逐一对照选择。3.1 只是想在 doLoginHandle 里获取除 name、pwd 以外的参数doLoginHandle只显式接收name、pwd但请求对象是完整的——在策略函数内部或任意能拿到请求上下文的代码处直接通过SaHolder读取前端提交的其他参数即可// 在任意代码处获取前端提交的参数 String xxx SaHolder.getRequest().getParam(xxx);适合「登录需要附带验证码、设备指纹、来源标记」等场景无需改动任何路由。3.2 想完全自定义一个接口来接受前端登录请求直接定义一个拦截路由为/oauth2/doLogin的 Controller 接口即可由 Spring MVC 的 URL 映射优先级决定请求先进入你的接口// 直接定义一个拦截路由为 /oauth2/doLogin 的接口即可 RequestMapping(/oauth2/doLogin) public SaResult ss(String name, String pwd) { System.out.println(------ 请求进入了自定义的API接口 ---------- ); if(sa.equals(name) 123456.equals(pwd)) { StpUtil.login(10001); return SaResult.ok(登录成功); } return SaResult.error(登录失败); }这种方式把「参数解析、鉴权逻辑、返回结构」全部交给业务代码doLoginHandle策略则完全闲置。3.3 不想使用 /oauth2/doLogin想自定义一个 API 地址答直接在前端更改点击按钮时 Ajax 的请求地址即可。例如登录按钮改为请求/user/login该接口由你自己的 Controller 处理内部同样调用StpUtil.login()建立 Sa-Token 会话——只要登录视图最终能让会话处于已登录状态/oauth2/authorize的后续流程就能正常继续。四、自定义 OAuth-Server 端的确认授权视图confirmView重写SaOAuth2Strategy.instance.confirmView策略其函数签名接收两个参数clientId应用 id与scopes本次申请的权限列表类型为ListStringAutowired public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) { // 配置授权确认视图 SaOAuth2Strategy.instance.confirmView (clientId, scopes) - { MapString, Object map new HashMap(); map.put(clientId, clientId); map.put(scope, scopes); return new ModelAndView(confirm.html, map); }; }从源码结构看该视图的触发条件是用户申请的 Scope 尚未授权过oauth2Template.isNeedCarefulConfirm(loginId, clientId, scopes)返回 true且客户端SaClientModel.isAutoConfirm为 false见 SaOAuth2ServerProcessor.java#L142-L149。若客户端设置了自动确认则跳过确认页直接重定向。因此 confirmView 页面中可以基于传入的clientId、scopes向用户展示「应用 X 正在申请读取你的 openid、userid」这类提示。授权确认页如何完成授权调用 /oauth2/doConfirm在返回的确认视图中ajax 方式调用/oauth2/doConfirm接口即可完成授权该接口接受以下参数参数是否必填说明client_id是应用 idscope是具体授予的权限多个用逗号或空格隔开response_type是取当前授权页 URL 上的response_type参数提交redirect_uri是取当前授权页 URL 上的redirect_uri参数提交state否取当前授权页 URL 上的state参数提交由于参数与授权页 URL 上的 query 一一对应官方推荐直接透传当前页面的 query 参数一行代码即可fetch(/oauth2/doConfirm location.search, {method: POST});接口成功时的返回值样例{ code: 200, msg: ok, data: null, }doConfirm 源码里的两个重要细节对照 SaOAuth2ServerProcessor.doConfirm()#L238-L295有两点值得注意该接口只允许 POST 方式非 POST 请求会抛出无效请求方式异常错误码 30151。这也解释了上文推荐示例中{method: POST}的写法。接口内部依次执行校验客户端存在checkClientModel→ 校验 Scope 签约checkContractScope→ 校验授权模式开启checkAuthorizeResponseType→ 校验重定向域名合法checkRedirectUri→ 落库本次授权saveGrantScope全部通过后返回SaResult.ok()。源码中还支持一个文档未提及的附加参数build_redirect_uritrue提交后服务端不会只返回 ok而是直接在下发结果中附上拼装好的最终redirect_uri含 code 或 access_token前端拿到后直接跳转即可省去「再请求 authorize 走一遍重定向」的步骤。五、完整参考实现demo 认证端 Server将以上三处策略定制与请求分发入口放在一起就是官方 demo 认证端的完整形态SaOAuth2ServerController.javaRestController public class SaOAuth2ServerController { // OAuth2-Server 端处理所有 OAuth2 相关请求 RequestMapping(/oauth2/*) public Object request() { return SaOAuth2ServerProcessor.instance.dister(); } // Sa-Token OAuth2 定制化配置 Autowired public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) { // 未登录的视图 SaOAuth2Strategy.instance.notLoginView () - new ModelAndView(login.html); // 登录处理函数 SaOAuth2Strategy.instance.doLoginHandle (name, pwd) - { if(sa.equals(name) 123456.equals(pwd)) { StpUtil.login(10001); return SaResult.ok().set(satoken, StpUtil.getTokenValue()); } return SaResult.error(账号名或密码错误); }; // 授权确认视图 SaOAuth2Strategy.instance.confirmView (clientId, scopes) - { MapString, Object map new HashMap(); map.put(clientId, clientId); map.put(scope, scopes); return new ModelAndView(confirm.html, map); }; } }配套的login.html/confirm.html静态页面可参考 demo 目录sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server与 H5 版本 sa-token-demo-oauth2-server-h5 中的实现单测侧则可在 OAuth2TestSupport 中查看针对notLoginView、confirmView、doLoginHandle的策略打桩方式作为行为验证的参照。六、小结定制点与触发时机速查定制对象策略/接口触发时机源码依据返回内容登录视图notLoginViewauthorize()中getLoginIdDefaultNull()为 null 时登录页视图如ModelAndView登录接口/oauth2/doLogindoLoginHandle前端登录页 ajax 调用参数仅name、pwd由策略自由决定SaResult等授权确认视图confirmView用户未授权本次 Scope 且客户端非isAutoConfirm时确认页视图参数clientId、scopes确认授权接口/oauth2/doConfirm前端确认页 ajax 调用仅 POST默认{code:200,msg:ok,data:null}build_redirect_uritrue时附带最终重定向地址需要说明的适用前提以上均针对作为「认证中心」的 OAuth-Server 端即引入了sa-token-oauth2模块并配置SaOAuth2ServerConfig的一方客户端接入方的登录跳转、code 换 token 等流程不受这些视图定制影响。【免费下载链接】Sa-Token✨ 开源、免费、一站式 Java 权限认证框架让鉴权变得简单、优雅—— 登录认证、权限认证、分布式 Session 会话、微服务网关鉴权、SSO 单点登录、OAuth2.0 统一认证、jwt 集成、API Key 秘钥授权、API 参数签名项目地址: https://gitcode.com/GitHub_Trending/sa/Sa-Token创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考