From c4e34704d5a2dc7ce4dd7d637a0ee72778e4d10d Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 11 May 2025 14:27:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(oauth2):=20=E5=AF=B9=20OAuth2=20Password?= =?UTF-8?q?=20=E8=AE=A4=E8=AF=81=E6=A8=A1=E5=BC=8F=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E9=87=8D=E5=86=99=E5=A4=84=E7=90=86=E5=99=A8=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BC=BA=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomPasswordGrantTypeHandler.java | 27 +++++++ .../oauth2/h5/SaOAuth2ServerH5Controller.java | 8 +- sa-token-doc/oauth2/readme.md | 10 +-- .../oauth2/error/SaOAuth2ErrorCode.java | 3 + .../handler/PasswordGrantTypeHandler.java | 15 ++-- .../handler/model/PasswordAuthResult.java | 75 +++++++++++++++++++ .../oauth2/strategy/SaOAuth2Strategy.java | 2 +- 7 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/custom/CustomPasswordGrantTypeHandler.java create mode 100644 sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/model/PasswordAuthResult.java diff --git a/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/custom/CustomPasswordGrantTypeHandler.java b/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/custom/CustomPasswordGrantTypeHandler.java new file mode 100644 index 00000000..dce85d0a --- /dev/null +++ b/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/custom/CustomPasswordGrantTypeHandler.java @@ -0,0 +1,27 @@ +//package com.pj.oauth2.custom; +// +//import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception; +//import cn.dev33.satoken.oauth2.granttype.handler.PasswordGrantTypeHandler; +//import cn.dev33.satoken.oauth2.granttype.handler.model.PasswordAuthResult; +//import org.springframework.stereotype.Component; +// +///** +// * 自定义 Password Grant_Type 授权模式处理器认证过程 +// * +// * @author click33 +// * @since 2025/5/11 +// */ +//@Component +//public class CustomPasswordGrantTypeHandler extends PasswordGrantTypeHandler { +// +// @Override +// public PasswordAuthResult loginByUsernamePassword(String username, String password) { +// if("sa".equals(username) && "123456".equals(password)) { +// long userId = 10001; +// return new PasswordAuthResult(userId); +// } else { +// throw new SaOAuth2Exception("无效账号密码"); +// } +// } +// +//} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/h5/SaOAuth2ServerH5Controller.java b/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/h5/SaOAuth2ServerH5Controller.java index bf63123e..92a91680 100644 --- a/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/h5/SaOAuth2ServerH5Controller.java +++ b/sa-token-demo/sa-token-demo-oauth2/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/h5/SaOAuth2ServerH5Controller.java @@ -8,6 +8,7 @@ import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts; import cn.dev33.satoken.oauth2.data.generate.SaOAuth2DataGenerate; import cn.dev33.satoken.oauth2.data.model.AccessTokenModel; import cn.dev33.satoken.oauth2.data.model.CodeModel; +import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel; import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel; import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode; import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception; @@ -63,8 +64,11 @@ public class SaOAuth2ServerH5Controller { // 6、判断:如果此次申请的Scope,该用户尚未授权,则转到授权页面 boolean isNeedCarefulConfirm = oauth2Template.isNeedCarefulConfirm(ra.loginId, ra.clientId, ra.scopes); if(isNeedCarefulConfirm) { - // code=411,需要用户手动确认授权 - return SaResult.get(411, "need confirm", null); + SaClientModel cm = oauth2Template.checkClientModel(ra.clientId); + if( ! cm.getIsAutoConfirm()) { + // code=411,需要用户手动确认授权 + return SaResult.get(411, "need confirm", null); + } } // 7、判断授权类型,重定向到不同地址 diff --git a/sa-token-doc/oauth2/readme.md b/sa-token-doc/oauth2/readme.md index fc93dcfa..43b5a117 100644 --- a/sa-token-doc/oauth2/readme.md +++ b/sa-token-doc/oauth2/readme.md @@ -31,11 +31,11 @@ OAuth2.0 与 SSO 相比,增加了对应用授权范围的控制,减弱了应 ### OAuth2.0 第三方开放平台完整开发流程参考 1. oauth2-server 平台端 - 1. 搭建 oauth2-server 数据后台管理端(后台人员对底层数据增删改查维护的地方)。 - 2. 搭建 oauth2-server 数据前台申请端(给第三方公司提供一个申请注册 client 的地方)。 - 3. 搭建 oauth2-server 授权端 以及其接口文档(让第三方公司拿到 access_token)。 - 4. 搭建 oauth2-server 资源端 以及其接口文档(让第三方公司通过 access_token 拿到对应的资源数据)。 - 5. 以上四端可以为一个项目,也可以为四个独立的项目。 + 1. 搭建 oauth2-server 数据后台管理端,也称:后台管理。(后台人员对底层数据增删改查维护的地方)。 + 2. 搭建 oauth2-server 数据前台申请端,也称:开放平台。(给第三方公司提供一个申请注册 client 的地方) + 3. 搭建 oauth2-server 授权端 以及其接口文档,也称:认证中心。(让第三方公司拿到 access_token) + 4. 搭建 oauth2-server 资源端 以及其接口文档,也称:资源中心。(让第三方公司通过 access_token 拿到对应的资源数据) + 5. 以上四端可以是一个项目,也可以是四个独立的项目,也可以是一个后端 + 多个前端的形式。 2. oauth2-client 第三方公司端 1. 第三方公司登录 oauth-server 数据前台申请端,申请注册应用,拿到 `clientId`、`clientSecret` 等数据。 diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/error/SaOAuth2ErrorCode.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/error/SaOAuth2ErrorCode.java index 37026d7e..8051ec1d 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/error/SaOAuth2ErrorCode.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/error/SaOAuth2ErrorCode.java @@ -104,6 +104,9 @@ public interface SaOAuth2ErrorCode { /** 无效的请求 Method */ int CODE_30151 = 30151; + /** Password 模式认证失败 */ + int CODE_30161 = 30161; + /** 其它异常 */ int CODE_30191 = 30191; diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/PasswordGrantTypeHandler.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/PasswordGrantTypeHandler.java index 40c3d054..40a217b7 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/PasswordGrantTypeHandler.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/PasswordGrantTypeHandler.java @@ -21,7 +21,9 @@ import cn.dev33.satoken.oauth2.consts.GrantType; import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts; import cn.dev33.satoken.oauth2.data.model.AccessTokenModel; import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel; +import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode; import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception; +import cn.dev33.satoken.oauth2.granttype.handler.model.PasswordAuthResult; import cn.dev33.satoken.stp.StpUtil; import java.util.List; @@ -47,10 +49,10 @@ public class PasswordGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterfa String password = req.getParamNotNull(SaOAuth2Consts.Param.password); // 3、调用API 开始登录,如果没能成功登录,则直接退出 - loginByUsernamePassword(username, password); - Object loginId = StpUtil.getLoginIdDefaultNull(); + PasswordAuthResult passwordAuthResult = loginByUsernamePassword(username, password); + Object loginId = passwordAuthResult.getLoginId(); if(loginId == null) { - throw new SaOAuth2Exception("登录失败"); + throw new SaOAuth2Exception("登录失败").setCode(SaOAuth2ErrorCode.CODE_30161); } // 4、构建 ra 对象 @@ -65,12 +67,15 @@ public class PasswordGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterfa } /** - * 根据 username、password 进行登录,如果登录失败请直接抛出异常 + * 根据 username、password 进行登录,如果登录失败请直接抛出异常或返回 loginId = null * @param username / * @param password / */ - public void loginByUsernamePassword(String username, String password) { + public PasswordAuthResult loginByUsernamePassword(String username, String password) { + System.err.println("当前暂未重写 PasswordGrantTypeHandler 处理器,将使用默认实现,仅供开发测试"); SaOAuth2Manager.getServerConfig().doLoginHandle.apply(username, password); + Object loginId = StpUtil.getLoginIdDefaultNull(); + return new PasswordAuthResult(loginId); } } \ No newline at end of file diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/model/PasswordAuthResult.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/model/PasswordAuthResult.java new file mode 100644 index 00000000..b6ce7b1a --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/model/PasswordAuthResult.java @@ -0,0 +1,75 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.oauth2.granttype.handler.model; + +import java.io.Serializable; + +/** + * Model: Password Grant_Type 认证结果 + * + * @author click33 + * @since 1.43.0 + */ +public class PasswordAuthResult implements Serializable { + + private static final long serialVersionUID = -6541180061782004705L; + + /** + * 对应账号id + */ + public Object loginId; + + /** + * 构建一个 + */ + public PasswordAuthResult() { + + } + /** + * 构建一个 + * @param loginId 对应的账号id + */ + public PasswordAuthResult(Object loginId) { + this(); + this.loginId = loginId; + } + + /** + * 获取 对应账号id + * @return / + */ + public Object getLoginId() { + return loginId; + } + + /** + * 设置 对应账号id + * @param loginId 对应账号id + * @return 对象自身 + */ + public PasswordAuthResult setLoginId(Object loginId) { + this.loginId = loginId; + return this; + } + + @Override + public String toString() { + return "PasswordAuthResult{" + + ", loginId=" + loginId + + '}'; + } + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/strategy/SaOAuth2Strategy.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/strategy/SaOAuth2Strategy.java index 83c73217..438d861d 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/strategy/SaOAuth2Strategy.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/strategy/SaOAuth2Strategy.java @@ -173,7 +173,7 @@ public final class SaOAuth2Strategy { } /** - * 根据 scope 信息对一个 AccessTokenModel 进行加工处理 + * 根据 grantType 构造一个 AccessTokenModel */ public SaOAuth2GrantTypeAuthFunction grantTypeAuth = (req) -> { String grantType = req.getParamNotNull(SaOAuth2Consts.Param.grant_type);