sa-token-oauth2 新增自定义 grant_type 能力

This commit is contained in:
click33
2024-08-23 03:24:30 +08:00
parent 4aa4941598
commit 3345e3aaf9
22 changed files with 778 additions and 277 deletions

View File

@@ -26,6 +26,9 @@ import cn.dev33.satoken.oauth2.data.loader.SaOAuth2DataLoader;
import cn.dev33.satoken.oauth2.data.loader.SaOAuth2DataLoaderDefaultImpl;
import cn.dev33.satoken.oauth2.data.resolver.SaOAuth2DataResolver;
import cn.dev33.satoken.oauth2.data.resolver.SaOAuth2DataResolverDefaultImpl;
import cn.dev33.satoken.oauth2.template.SaOAuth2Template;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
/**
* Sa-Token-OAuth2 模块 总控类
@@ -144,4 +147,40 @@ public class SaOAuth2Manager {
SaOAuth2Manager.dao = dao;
}
/**
* OAuth2 模板方法 Bean
*/
private static volatile SaOAuth2Template template;
public static SaOAuth2Template getTemplate() {
if (template == null) {
synchronized (SaOAuth2Manager.class) {
if (template == null) {
setTemplate(new SaOAuth2Template());
}
}
}
return template;
}
public static void setTemplate(SaOAuth2Template template) {
SaOAuth2Manager.template = template;
}
/**
* OAuth2 StpLogic
*/
private static volatile StpLogic stpLogic;
public static StpLogic getStpLogic() {
if (stpLogic == null) {
synchronized (SaOAuth2Manager.class) {
if (stpLogic == null) {
setStpLogic(StpUtil.stpLogic);
}
}
}
return stpLogic;
}
public static void setStpLogic(StpLogic stpLogic) {
SaOAuth2Manager.stpLogic = stpLogic;
}
}

View File

@@ -0,0 +1,12 @@
package cn.dev33.satoken.oauth2.consts;
/**
* 所有授权类型
*/
public final class GrantType {
public static String authorization_code = "authorization_code";
public static String refresh_token = "refresh_token";
public static String password = "password";
public static String client_credentials = "client_credentials";
public static String implicit = "implicit";
}

View File

@@ -68,17 +68,6 @@ public class SaOAuth2Consts {
public static String token = "token";
}
/**
* 所有授权类型
*/
public static final class GrantType {
public static String authorization_code = "authorization_code";
public static String refresh_token = "refresh_token";
public static String password = "password";
public static String client_credentials = "client_credentials";
public static String implicit = "implicit";
}
/**
* 所有 token 类型
*/

View File

@@ -35,21 +35,21 @@ public interface SaOAuth2DataGenerate {
* @param ra 请求参数Model
* @return 授权码Model
*/
public CodeModel generateCode(RequestAuthModel ra);
CodeModel generateCode(RequestAuthModel ra);
/**
* 构建ModelAccess-Token
* @param code 授权码Model
* @return AccessToken Model
*/
public AccessTokenModel generateAccessToken(String code);
AccessTokenModel generateAccessToken(String code);
/**
* 刷新Model根据 Refresh-Token 生成一个新的 Access-Token
* @param refreshToken Refresh-Token值
* @return 新的 Access-Token
*/
public AccessTokenModel refreshAccessToken(String refreshToken);
AccessTokenModel refreshAccessToken(String refreshToken);
/**
* 构建ModelAccess-Token (根据RequestAuthModel构建用于隐藏式 and 密码式)
@@ -57,7 +57,7 @@ public interface SaOAuth2DataGenerate {
* @param isCreateRt 是否生成对应的Refresh-Token
* @return Access-Token Model
*/
public AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt);
AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt);
/**
* 构建ModelClient-Token
@@ -65,7 +65,7 @@ public interface SaOAuth2DataGenerate {
* @param scopes 授权范围
* @return Client-Token Model
*/
public ClientTokenModel generateClientToken(String clientId, List<String> scopes);
ClientTokenModel generateClientToken(String clientId, List<String> scopes);
/**
* 构建URL下放Code URL (Authorization Code 授权码)
@@ -74,7 +74,7 @@ public interface SaOAuth2DataGenerate {
* @param state state参数
* @return 构建完毕的URL
*/
public String buildRedirectUri(String redirectUri, String code, String state);
String buildRedirectUri(String redirectUri, String code, String state);
/**
* 构建URL下放Access-Token URL implicit 隐藏式)
@@ -83,14 +83,12 @@ public interface SaOAuth2DataGenerate {
* @param state state参数
* @return 构建完毕的URL
*/
public String buildImplicitRedirectUri(String redirectUri, String token, String state);
String buildImplicitRedirectUri(String redirectUri, String token, String state);
/**
* 回收 Access-Token
* @param accessToken Access-Token值
*/
public void revokeAccessToken(String accessToken);
void revokeAccessToken(String accessToken);
}

View File

@@ -52,25 +52,11 @@ public class SaClientModel implements Serializable {
* 应用允许授权的所有URL
*/
public List<String> allowUrls;
/** 此 Client 是否打开模式授权码Authorization Code */
public Boolean enableCode = false;
/** 此 Client 是否打开模式隐藏式Implicit */
public Boolean enableImplicit = false;
/** 此 Client 是否打开模式密码式Password */
public Boolean enablePassword = false;
/** 此 Client 是否打开模式凭证式Client Credentials */
public Boolean enableClient = false;
// /**
// * 是否自动判断此 Client 开放的授权模式
// * <br> 此值为true时四种模式isCode、isImplicit、isPassword、isClient是否生效依靠全局设置
// * <br> 此值为false时四种模式isCode、isImplicit、isPassword、isClient是否生效依靠局部配置+全局配置
// */
// public Boolean isAutoMode = true;
/**
* 应用允许的所有 grant_type
*/
public List<String> allowGrantTypes = new ArrayList<>();
/** 单独配置此Client是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token [默认取全局配置] */
public Boolean isNewRefresh;
@@ -169,86 +155,22 @@ public class SaClientModel implements Serializable {
}
/**
* @return 此 Client 是否打开模式授权码Authorization Code
* @return 应用允许的所有 grant_type
*/
public Boolean getEnableCode() {
return enableCode;
public List<String> getAllowGrantTypes() {
return allowGrantTypes;
}
/**
* @param enableCode 此 Client 是否打开模式授权码Authorization Code
* @return 对象自身
* 应用允许的所有 grant_type
* @param allowGrantTypes /
* @return /
*/
public SaClientModel setEnableCode(Boolean enableCode) {
this.enableCode = enableCode;
public SaClientModel setAllowGrantTypes(List<String> allowGrantTypes) {
this.allowGrantTypes = allowGrantTypes;
return this;
}
/**
* @return 此 Client 是否打开模式隐藏式Implicit
*/
public Boolean getEnableImplicit() {
return enableImplicit;
}
/**
* @param enableImplicit 此 Client 是否打开模式隐藏式Implicit
* @return 对象自身
*/
public SaClientModel setEnableImplicit(Boolean enableImplicit) {
this.enableImplicit = enableImplicit;
return this;
}
/**
* @return 此 Client 是否打开模式密码式Password
*/
public Boolean getEnablePassword() {
return enablePassword;
}
/**
* @param enablePassword 此 Client 是否打开模式密码式Password
* @return 对象自身
*/
public SaClientModel setEnablePassword(Boolean enablePassword) {
this.enablePassword = enablePassword;
return this;
}
/**
* @return 此 Client 是否打开模式凭证式Client Credentials
*/
public Boolean getEnableClient() {
return enableClient;
}
/**
* @param enableClient 此 Client 是否打开模式凭证式Client Credentials
* @return 对象自身
*/
public SaClientModel setEnableClient(Boolean enableClient) {
this.enableClient = enableClient;
return this;
}
//
// /**
// * @return 是否自动判断此 Client 开放的授权模式
// */
// public Boolean getIsAutoMode() {
// return isAutoMode;
// }
//
// /**
// * @param isAutoMode 是否自动判断此 Client 开放的授权模式
// * @return 对象自身
// */
// public SaClientModel setIsAutoMode(Boolean isAutoMode) {
// this.isAutoMode = isAutoMode;
// return this;
// }
//
/**
* @return 此Client是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token [默认取全局配置]
*/
@@ -338,11 +260,7 @@ public class SaClientModel implements Serializable {
", clientSecret='" + clientSecret + '\'' +
", contractScopes=" + contractScopes +
", allowUrls=" + allowUrls +
", isCode=" + enableCode +
", isImplicit=" + enableImplicit +
", isPassword=" + enablePassword +
", isClient=" + enableClient +
// ", isAutoMode=" + isAutoMode +
", allowGrantTypes=" + allowGrantTypes +
", isNewRefresh=" + isNewRefresh +
", accessTokenTimeout=" + accessTokenTimeout +
", refreshTokenTimeout=" + refreshTokenTimeout +
@@ -367,7 +285,7 @@ public class SaClientModel implements Serializable {
}
/**
* @param urls 添加应用签约的所有权限
* @param urls 添加应用允许授权的所有URL
* @return 对象自身
*/
public SaClientModel addAllowUrls(String... urls) {
@@ -378,5 +296,17 @@ public class SaClientModel implements Serializable {
return this;
}
/**
* @param grantTypes 应用允许的所有 grant_type
* @return 对象自身
*/
public SaClientModel addAllowGrantTypes(String... grantTypes) {
if(this.allowGrantTypes == null) {
this.allowGrantTypes = new ArrayList<>();
}
this.allowGrantTypes.addAll(Arrays.asList(grantTypes));
return this;
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.function.strategy;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import java.util.function.Function;
/**
* 函数式接口GrantType 认证
*
* <p> 参数SaRequest、grant_type </p>
* <p> 返回:处理结果 </p>
*
* @author click33
* @since 1.39.0
*/
@FunctionalInterface
public interface SaOAuth2GrantTypeAuthFunction extends Function<SaRequest, AccessTokenModel> {
}

View File

@@ -0,0 +1,57 @@
/*
* 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;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.consts.GrantType;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.request.ClientIdAndSecretModel;
import java.util.List;
/**
* authorization_code grant_type 处理器
*
* @author click33
* @since 1.39.0
*/
public class AuthorizationCodeGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterface {
@Override
public String getHandlerGrantType() {
return GrantType.authorization_code;
}
@Override
public AccessTokenModel getAccessTokenModel(SaRequest req, String clientId, List<String> scopes) {
// 获取参数
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
// String clientId = clientIdAndSecret.clientId;
String clientSecret = clientIdAndSecret.clientSecret;
String code = req.getParamNotNull(SaOAuth2Consts.Param.code);
String redirectUri = req.getParam(SaOAuth2Consts.Param.redirect_uri);
// 校验参数
SaOAuth2Manager.getTemplate().checkGainTokenParam(code, clientId, clientSecret, redirectUri);
// 构建 Access-Token、返回
AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().generateAccessToken(code);
return accessTokenModel;
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
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.exception.SaOAuth2Exception;
import cn.dev33.satoken.stp.StpUtil;
import java.util.List;
/**
* password grant_type 处理器
*
* @author click33
* @since 1.39.0
*/
public class PasswordGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterface {
@Override
public String getHandlerGrantType() {
return GrantType.password;
}
@Override
public AccessTokenModel getAccessTokenModel(SaRequest req, String clientId, List<String> scopes) {
// 1、获取请求参数
String username = req.getParamNotNull(SaOAuth2Consts.Param.username);
String password = req.getParamNotNull(SaOAuth2Consts.Param.password);
// 3、调用API 开始登录,如果没能成功登录,则直接退出
loginByUsernamePassword(username, password);
Object loginId = StpUtil.getLoginIdDefaultNull();
if(loginId == null) {
throw new SaOAuth2Exception("登录失败");
}
// 4、构建 ra 对象
RequestAuthModel ra = new RequestAuthModel();
ra.clientId = clientId;
ra.loginId = loginId;
ra.scopes = scopes;
// 5、生成 Access-Token
AccessTokenModel at = SaOAuth2Manager.getDataGenerate().generateAccessToken(ra, true);
return at;
}
/**
* 根据 username、password 进行登录,如果登录失败请直接抛出异常
* @param username /
* @param password /
*/
public void loginByUsernamePassword(String username, String password) {
SaOAuth2Manager.getConfig().doLoginHandle.apply(username, password);
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
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.RefreshTokenModel;
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import java.util.List;
/**
* refresh_token grant_type 处理器
*
* @author click33
* @since 1.39.0
*/
public class RefreshTokenGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterface {
@Override
public String getHandlerGrantType() {
return GrantType.refresh_token;
}
@Override
public AccessTokenModel getAccessTokenModel(SaRequest req, String clientId, List<String> scopes) {
// 获取参数
String refreshToken = req.getParamNotNull(SaOAuth2Consts.Param.refresh_token);
// 校验Refresh-Token 是否存在
RefreshTokenModel rt = SaOAuth2Manager.getDao().getRefreshToken(refreshToken);
SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken, SaOAuth2ErrorCode.CODE_30121);
// 校验Refresh-Token 代表的 ClientId 与提供的 ClientId 是否一致
SaOAuth2Exception.throwBy( ! rt.clientId.equals(clientId), "无效client_id: " + clientId, SaOAuth2ErrorCode.CODE_30122);
// 获取新 Access-Token
AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().refreshAccessToken(refreshToken);
return accessTokenModel;
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import java.util.List;
/**
* 所有 OAuth2 GrantType 处理器的父接口
*
* @author click33
* @since 1.39.0
*/
public interface SaOAuth2GrantTypeHandlerInterface {
/**
* 获取所要处理的 GrantType
*
* @return /
*/
String getHandlerGrantType();
/**
* 获取 AccessTokenModel 对象
*
* @param req /
* @return /
*/
AccessTokenModel getAccessTokenModel(SaRequest req, String clientId, List<String> scopes);
}

View File

@@ -20,9 +20,9 @@ import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.consts.GrantType;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.Api;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.GrantType;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.Param;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.ResponseType;
import cn.dev33.satoken.oauth2.data.generate.SaOAuth2DataGenerate;
@@ -34,10 +34,9 @@ import cn.dev33.satoken.oauth2.data.model.request.ClientIdAndSecretModel;
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.strategy.SaOAuth2Strategy;
import cn.dev33.satoken.oauth2.template.SaOAuth2Template;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import java.util.List;
@@ -55,11 +54,6 @@ public class SaOAuth2ServerProcessor {
*/
public static SaOAuth2ServerProcessor instance = new SaOAuth2ServerProcessor();
/**
* 底层 SaOAuth2Template 对象
*/
public SaOAuth2Template oauth2Template = new SaOAuth2Template();
/**
* 处理 Server 端请求, 路由分发
* @return 处理结果
@@ -68,7 +62,6 @@ public class SaOAuth2ServerProcessor {
// 获取变量
SaRequest req = SaHolder.getRequest();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
// ------------------ 路由分发 ------------------
@@ -79,7 +72,7 @@ public class SaOAuth2ServerProcessor {
// Code 换 Access-Token || 模式三:密码式
if(req.isPath(Api.token)) {
return tokenOrPassword();
return token();
}
// Refresh-Token 刷新 Access-Token
@@ -122,18 +115,19 @@ public class SaOAuth2ServerProcessor {
SaResponse res = SaHolder.getResponse();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
String responseType = req.getParamNotNull(Param.response_type);
// 1、先判断是否开启了指定的授权模式
checkAuthorizeResponseType(responseType, req, cfg);
// 2、如果尚未登录, 则先去登录
if( ! getStpLogic().isLogin()) {
if( ! SaOAuth2Manager.getStpLogic().isLogin()) {
return cfg.notLoginView.get();
}
// 3、构建请求 Model
RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, getStpLogic().getLoginId());
RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, SaOAuth2Manager.getStpLogic().getLoginId());
// 4、校验重定向域名是否合法
oauth2Template.checkRightUrl(ra.clientId, ra.redirectUri);
@@ -167,55 +161,11 @@ public class SaOAuth2ServerProcessor {
}
/**
* Code 换 Access-Token || 模式三:密码式
* @return 处理结果
*/
public Object tokenOrPassword() {
String grantType = SaHolder.getRequest().getParamNotNull(Param.grant_type);
// Code 换 Access-Token
if(grantType.equals(GrantType.authorization_code)) {
return token();
}
// 模式三:密码式
if(grantType.equals(GrantType.password)) {
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
if(!cfg.enablePassword) {
throwErrorSystemNotEnableModel();
}
if(!currClientModel().enablePassword) {
throwErrorClientNotEnableModel();
}
return password();
}
throw new SaOAuth2Exception("无效 grant_type" + grantType);
}
/**
* Code授权码 获取 Access-Token
* Code 换 Access-Token / 模式三:密码式 / 自定义 grant_type
* @return 处理结果
*/
public Object token() {
// 获取变量
SaRequest req = SaHolder.getRequest();
// 获取参数
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
String clientId = clientIdAndSecret.clientId;
String clientSecret = clientIdAndSecret.clientSecret;
String code = req.getParamNotNull(Param.code);
String redirectUri = req.getParam(Param.redirect_uri);
// 校验参数
oauth2Template.checkGainTokenParam(code, clientId, clientSecret, redirectUri);
// 构建 Access-Token
AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().generateAccessToken(code);
// 返回
AccessTokenModel accessTokenModel = SaOAuth2Strategy.instance.grantTypeAuth.apply(SaHolder.getRequest());
return SaOAuth2Manager.getDataResolver().buildTokenReturnValue(accessTokenModel);
}
@@ -224,27 +174,10 @@ public class SaOAuth2ServerProcessor {
* @return 处理结果
*/
public Object refresh() {
// 获取变量
SaRequest req = SaHolder.getRequest();
String grantType = req.getParamNotNull(Param.grant_type);
if(!grantType.equals(GrantType.refresh_token)) {
throw new SaOAuth2Exception("无效 grant_type" + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
}
// 获取参数
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
String clientId = clientIdAndSecret.clientId;
String clientSecret = clientIdAndSecret.clientSecret;
String refreshToken = req.getParamNotNull(Param.refresh_token);
// 校验参数
oauth2Template.checkRefreshTokenParam(clientId, clientSecret, refreshToken);
// 获取新 Access-Token
AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().refreshAccessToken(refreshToken);
// 返回
SaOAuth2Exception.throwBy(!grantType.equals(GrantType.refresh_token), "无效 grant_type" + grantType, SaOAuth2ErrorCode.CODE_30126);
AccessTokenModel accessTokenModel = SaOAuth2Strategy.instance.grantTypeAuth.apply(req);
return SaOAuth2Manager.getDataResolver().buildRefreshTokenReturnValue(accessTokenModel);
}
@@ -254,6 +187,7 @@ public class SaOAuth2ServerProcessor {
*/
public Object revoke() {
// 获取变量
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
SaRequest req = SaHolder.getRequest();
// 获取参数
@@ -297,10 +231,11 @@ public class SaOAuth2ServerProcessor {
// 获取变量
SaRequest req = SaHolder.getRequest();
String clientId = req.getParamNotNull(Param.client_id);
Object loginId = getStpLogic().getLoginId();
Object loginId = SaOAuth2Manager.getStpLogic().getLoginId();
String scope = req.getParamNotNull(Param.scope);
List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(scope);
SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
// 此请求只允许 POST 方式
if(!req.isMethod(SaHttpMethod.POST)) {
@@ -343,49 +278,6 @@ public class SaOAuth2ServerProcessor {
throw new SaOAuth2Exception("无效response_type: " + ra.responseType).setCode(SaOAuth2ErrorCode.CODE_30125);
}
/**
* 模式三:密码式
* @return 处理结果
*/
public Object password() {
// 获取变量
SaRequest req = SaHolder.getRequest();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
// 1、获取请求参数
String username = req.getParamNotNull(Param.username);
String password = req.getParamNotNull(Param.password);
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
String clientId = clientIdAndSecret.clientId;
String clientSecret = clientIdAndSecret.clientSecret;
String scope = req.getParam(Param.scope, "");
List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(scope);
// 2、校验 ClientScope 和 scope
oauth2Template.checkClientSecretAndScope(clientId, clientSecret, scopes);
// 3、防止因前端误传token造成逻辑干扰
// SaHolder.getStorage().set(getStpLogic().stpLogic.splicingKeyJustCreatedSave(), "no-token");
// 3、调用API 开始登录,如果没能成功登录,则直接退出
Object retObj = cfg.doLoginHandle.apply(username, password);
if( ! getStpLogic().isLogin()) {
return retObj;
}
// 4、构建 ra对象
RequestAuthModel ra = new RequestAuthModel();
ra.clientId = clientId;
ra.loginId = getStpLogic().getLoginId();
ra.scopes = scopes;
// 5、生成 Access-Token
AccessTokenModel at = SaOAuth2Manager.getDataGenerate().generateAccessToken(ra, true);
// 6、返回 Access-Token
return SaOAuth2Manager.getDataResolver().buildPasswordReturnValue(at);
}
/**
* 模式四:凭证式
* @return 处理结果
@@ -394,6 +286,7 @@ public class SaOAuth2ServerProcessor {
// 获取变量
SaRequest req = SaHolder.getRequest();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
String grantType = req.getParamNotNull(Param.grant_type);
if(!grantType.equals(GrantType.client_credentials)) {
@@ -402,7 +295,7 @@ public class SaOAuth2ServerProcessor {
if(!cfg.enableClient) {
throwErrorSystemNotEnableModel();
}
if(!currClientModel().enableClient) {
if(!currClientModel().getAllowGrantTypes().contains(GrantType.client_credentials)) {
throwErrorClientNotEnableModel();
}
@@ -434,6 +327,7 @@ public class SaOAuth2ServerProcessor {
* @return /
*/
public SaClientModel currClientModel() {
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(SaHolder.getRequest());
return oauth2Template.checkClientModel(clientIdAndSecret.clientId);
}
@@ -447,7 +341,7 @@ public class SaOAuth2ServerProcessor {
if(!cfg.enableCode) {
throwErrorSystemNotEnableModel();
}
if(!currClientModel().enableCode) {
if(!currClientModel().getAllowGrantTypes().contains(GrantType.authorization_code)) {
throwErrorClientNotEnableModel();
}
}
@@ -456,7 +350,7 @@ public class SaOAuth2ServerProcessor {
if(!cfg.enableImplicit) {
throwErrorSystemNotEnableModel();
}
if(!currClientModel().enableImplicit) {
if(!currClientModel().getAllowGrantTypes().contains(GrantType.implicit)) {
throwErrorClientNotEnableModel();
}
}
@@ -466,15 +360,6 @@ public class SaOAuth2ServerProcessor {
}
}
/**
* 获取底层使用的会话对象
*
* @return /
*/
public StpLogic getStpLogic() {
return StpUtil.stpLogic;
}
/**
* 系统未开放此授权模式时抛出异常
*/

View File

@@ -16,8 +16,18 @@
package cn.dev33.satoken.oauth2.strategy;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.consts.GrantType;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
import cn.dev33.satoken.oauth2.data.model.request.ClientIdAndSecretModel;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.oauth2.function.strategy.*;
import cn.dev33.satoken.oauth2.granttype.handler.AuthorizationCodeGrantTypeHandler;
import cn.dev33.satoken.oauth2.granttype.handler.PasswordGrantTypeHandler;
import cn.dev33.satoken.oauth2.granttype.handler.RefreshTokenGrantTypeHandler;
import cn.dev33.satoken.oauth2.granttype.handler.SaOAuth2GrantTypeHandlerInterface;
import cn.dev33.satoken.oauth2.scope.CommonScope;
import cn.dev33.satoken.oauth2.scope.handler.OidcScopeHandler;
import cn.dev33.satoken.oauth2.scope.handler.OpenIdScopeHandler;
@@ -26,6 +36,7 @@ import cn.dev33.satoken.oauth2.scope.handler.UserIdScopeHandler;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
@@ -38,6 +49,7 @@ public final class SaOAuth2Strategy {
private SaOAuth2Strategy() {
registerDefaultScopeHandler();
registerDefaultGrantTypeHandler();
}
/**
@@ -78,9 +90,6 @@ public final class SaOAuth2Strategy {
scopeHandlerMap.remove(scope);
}
// ----------------------- 所有策略
/**
* 根据 scope 信息对一个 AccessTokenModel 进行加工处理
*/
@@ -117,6 +126,75 @@ public final class SaOAuth2Strategy {
}
};
// grant_type 处理器
/**
* grant_type 处理器集合
*/
public Map<String, SaOAuth2GrantTypeHandlerInterface> grantTypeHandlerMap = new LinkedHashMap<>();
/**
* 注册所有默认的权限处理器
*/
public void registerDefaultGrantTypeHandler() {
grantTypeHandlerMap.put(GrantType.authorization_code, new AuthorizationCodeGrantTypeHandler());
grantTypeHandlerMap.put(GrantType.password, new PasswordGrantTypeHandler());
grantTypeHandlerMap.put(GrantType.refresh_token, new RefreshTokenGrantTypeHandler());
}
/**
* 注册一个权限处理器
*/
public void registerGrantTypeHandler(SaOAuth2GrantTypeHandlerInterface handler) {
grantTypeHandlerMap.put(handler.getHandlerGrantType(), handler);
// TODO 优化日志输出
SaManager.getLog().info("新增GrantType处理器" + handler.getHandlerGrantType());
// SaTokenEventCenter.doRegisterAnnotationHandler(handler);
}
/**
* 移除一个权限处理器
*/
public void removeGrantTypeHandler(String scope) {
scopeHandlerMap.remove(scope);
}
/**
* 根据 scope 信息对一个 AccessTokenModel 进行加工处理
*/
public SaOAuth2GrantTypeAuthFunction grantTypeAuth = (req) -> {
String grantType = req.getParamNotNull(SaOAuth2Consts.Param.grant_type);
SaOAuth2GrantTypeHandlerInterface grantTypeHandler = grantTypeHandlerMap.get(grantType);
if(grantTypeHandler == null) {
throw new RuntimeException("无效 grant_type: " + grantType);
}
// 看看全局是否开启了此 grantType
SaOAuth2Config config = SaOAuth2Manager.getConfig();
if(grantType.equals(GrantType.authorization_code) && !config.getEnableCode() ) {
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType);
}
if(grantType.equals(GrantType.password) && !config.getEnablePassword() ) {
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType);
}
// 校验 clientSecret 和 scope
ClientIdAndSecretModel clientIdAndSecretModel = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(req.getParam(SaOAuth2Consts.Param.scope));
SaClientModel clientModel = SaOAuth2Manager.getTemplate().checkClientSecretAndScope(clientIdAndSecretModel.getClientId(), clientIdAndSecretModel.getClientSecret(), scopes);
// 检测应用是否开启此 grantType
if(!clientModel.getAllowGrantTypes().contains(grantType)) {
throw new SaOAuth2Exception("应用未开放的 grant_type: " + grantType);
}
// 调用 处理器
return grantTypeHandler.getAccessTokenModel(req, clientIdAndSecretModel.getClientId(), scopes);
};
// ----------------------- 所有策略
/**
* 创建一个 code value
*/

View File

@@ -41,7 +41,7 @@ public class SaOAuth2Util {
* @return ClientModel
*/
public static SaClientModel checkClientModel(String clientId) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkClientModel(clientId);
return SaOAuth2Manager.getTemplate().checkClientModel(clientId);
}
/**
@@ -50,7 +50,7 @@ public class SaOAuth2Util {
* @return .
*/
public static AccessTokenModel checkAccessToken(String accessToken) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkAccessToken(accessToken);
return SaOAuth2Manager.getTemplate().checkAccessToken(accessToken);
}
/**
@@ -59,7 +59,7 @@ public class SaOAuth2Util {
* @return .
*/
public static ClientTokenModel checkClientToken(String clientToken) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkClientToken(clientToken);
return SaOAuth2Manager.getTemplate().checkClientToken(clientToken);
}
/**
@@ -68,7 +68,7 @@ public class SaOAuth2Util {
* @return LoginId
*/
public static Object getLoginIdByAccessToken(String accessToken) {
return SaOAuth2ServerProcessor.instance.oauth2Template.getLoginIdByAccessToken(accessToken);
return SaOAuth2Manager.getTemplate().getLoginIdByAccessToken(accessToken);
}
/**
@@ -77,7 +77,7 @@ public class SaOAuth2Util {
* @param scopes 需要校验的权限列表
*/
public static void checkScope(String accessToken, String... scopes) {
SaOAuth2ServerProcessor.instance.oauth2Template.checkScope(accessToken, scopes);
SaOAuth2Manager.getTemplate().checkScope(accessToken, scopes);
}
/**
@@ -86,7 +86,7 @@ public class SaOAuth2Util {
* @param scopes 需要校验的权限列表
*/
public static void checkClientTokenScope(String clientToken, String... scopes) {
SaOAuth2ServerProcessor.instance.oauth2Template.checkClientTokenScope(clientToken, scopes);
SaOAuth2Manager.getTemplate().checkClientTokenScope(clientToken, scopes);
}
@@ -100,7 +100,7 @@ public class SaOAuth2Util {
* @return 是否已经授权
*/
public static boolean isGrant(Object loginId, String clientId, List<String> scopes) {
return SaOAuth2ServerProcessor.instance.oauth2Template.isGrant(loginId, clientId, scopes);
return SaOAuth2Manager.getTemplate().isGrant(loginId, clientId, scopes);
}
/**
@@ -109,7 +109,7 @@ public class SaOAuth2Util {
* @param scopes 权限(多个用逗号隔开)
*/
public static void checkContract(String clientId, List<String> scopes) {
SaOAuth2ServerProcessor.instance.oauth2Template.checkContract(clientId, scopes);
SaOAuth2Manager.getTemplate().checkContract(clientId, scopes);
}
/**
@@ -118,7 +118,7 @@ public class SaOAuth2Util {
* @param url 指定url
*/
public static void checkRightUrl(String clientId, String url) {
SaOAuth2ServerProcessor.instance.oauth2Template.checkRightUrl(clientId, url);
SaOAuth2Manager.getTemplate().checkRightUrl(clientId, url);
}
/**
@@ -128,7 +128,7 @@ public class SaOAuth2Util {
* @return SaClientModel对象
*/
public static SaClientModel checkClientSecret(String clientId, String clientSecret) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkClientSecret(clientId, clientSecret);
return SaOAuth2Manager.getTemplate().checkClientSecret(clientId, clientSecret);
}
/**
@@ -139,7 +139,7 @@ public class SaOAuth2Util {
* @return SaClientModel对象
*/
public static SaClientModel checkClientSecretAndScope(String clientId, String clientSecret, List<String> scopes) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkClientSecretAndScope(clientId, clientSecret, scopes);
return SaOAuth2Manager.getTemplate().checkClientSecretAndScope(clientId, clientSecret, scopes);
}
/**
@@ -151,7 +151,7 @@ public class SaOAuth2Util {
* @return CodeModel对象
*/
public static CodeModel checkGainTokenParam(String code, String clientId, String clientSecret, String redirectUri) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkGainTokenParam(code, clientId, clientSecret, redirectUri);
return SaOAuth2Manager.getTemplate().checkGainTokenParam(code, clientId, clientSecret, redirectUri);
}
/**
@@ -162,7 +162,7 @@ public class SaOAuth2Util {
* @return CodeModel对象
*/
public static RefreshTokenModel checkRefreshTokenParam(String clientId, String clientSecret, String refreshToken) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkRefreshTokenParam(clientId, clientSecret, refreshToken);
return SaOAuth2Manager.getTemplate().checkRefreshTokenParam(clientId, clientSecret, refreshToken);
}
/**
@@ -173,7 +173,7 @@ public class SaOAuth2Util {
* @return SaClientModel对象
*/
public static AccessTokenModel checkAccessTokenParam(String clientId, String clientSecret, String accessToken) {
return SaOAuth2ServerProcessor.instance.oauth2Template.checkAccessTokenParam(clientId, clientSecret, accessToken);
return SaOAuth2Manager.getTemplate().checkAccessTokenParam(clientId, clientSecret, accessToken);
}
// ------------------- save 数据
@@ -185,7 +185,7 @@ public class SaOAuth2Util {
* @param scopes 权限列表
*/
public static void saveGrantScope(String clientId, Object loginId, List<String> scopes) {
SaOAuth2ServerProcessor.instance.oauth2Template.saveGrantScope(clientId, loginId, scopes);
SaOAuth2Manager.getTemplate().saveGrantScope(clientId, loginId, scopes);
}