优化 sa-token-oauth2 异常细分状态码

This commit is contained in:
click33 2024-08-26 02:34:34 +08:00
parent ffd557c5d7
commit b552dd334c
16 changed files with 195 additions and 129 deletions

View File

@ -56,19 +56,19 @@
- [OAuth2-Server搭建](/oauth2/oauth2-server)
- [OAuth2-Server端开放 API 接口](/oauth2/oauth2-apidoc)
- [配置 client 域名校验 ](/oauth2/oauth2-check-domain)
- [定制化登录页面与授权页面](/oauth2/oauth2-custom-login)
- [自定义 API 路由 ](/oauth2/oauth2-custom-api)
- [自定义 Scope 权限以处理器](/oauth2/oauth2-custom-scope)
- [自定义 Scope 权限及处理器](/oauth2/oauth2-custom-scope)
- [为 Scope 划分等级](/oauth2/oauth2-scope-level)
- [自定义 grant_type](/oauth2/oauth2-custom-grant_type)
- [定制化登录页面与授权页面](/oauth2/oauth2-custom-login)
- [自定义 API 路由 ](/oauth2/oauth2-custom-api)
- [开启 OIDC 协议](/oauth2/oauth2-oidc)
- [OAuth2-与登录会话实现数据互通](/oauth2/oauth2-interworking)
- [使用注解校验 Access-Token](/oauth2/oauth2-at-check)
- [OAuth2-与登录会话实现数据互通](/oauth2/oauth2-interworking)
- [OAuth2 代码 API 参考](/oauth2/oauth2-dev)
- [常见问题总结](/oauth2/oauth2-questions)
<!-- - [前后端分离模式整合方案](/oauth2/4) -->
<!-- - [平台中心模式开发](/oauth2/5) -->
- <!-- jwt风格token、使用注解校验权限、state参数详解 -->
<!-- - [jwt 风格 token](/oauth2/6) -->
- **微服务**
- [分布式Session会话](/micro/dcs-session)

View File

@ -311,9 +311,9 @@ clientId 反查 Client-Token
{tokenName}:oauth2:client-token-index:{clientId}
```
Past-Token 次级应用令牌索引
Lower-Client-Token 次级应用令牌索引
``` js
{tokenName}:oauth2:past-token-index:{clientId}
{tokenName}:oauth2:lower-client-token-index:{clientId}
```
### 3.5、用户授权记录

View File

@ -160,37 +160,32 @@ SaToken 中的所有异常都是继承于 `SaTokenException` 的,也就是说
#### sa-token-oauth2 相关:
| code码值 | 含义 |
| :-------- | :-------- |
| 30101 | client_id 不可为空 |
| 30102 | scope 不可为空 |
| code码值 | 含义 |
| :-------- | :-------- |
| 30101 | client_id 不可为空 |
| 30102 | scope 不可为空 |
| 30103 | redirect_uri 不可为空 |
| 30104 | LoginId 不可为空 |
| 30105 | 无效client_id |
| 30106 | 无效access_token |
| 30107 | 无效 client_token |
| 30108 | Access-Token 不具备指定的 Scope |
| 30109 | Client-Token 不具备指定的 Scope |
| 30110 | 无效 code 码 |
| 30111 | 无效 Refresh-Token |
| 30112 | 请求的Scope暂未签约 |
| 30113 | 无效redirect_url |
| 30114 | 非法redirect_url |
| 30115 | 无效client_secret |
| 30116 | 请求的Scope暂未签约 |
| 30117 | 无效code |
| 30118 | 无效client_id |
| 30119 | 无效client_secret |
| 30120 | 无效redirect_uri |
| 30121 | 无效refresh_token |
| 30122 | 无效client_id |
| 30123 | 无效client_secret |
| 30124 | 无效client_id |
| 30125 | 无效response_type |
| 30131 | 暂未开放授权码模式 |
| 30132 | 暂未开放隐藏式模式 |
| 30133 | 暂未开放密码式模式 |
| 30134 | 暂未开放凭证式模式 |
| 30104 | LoginId 不可为空 |
| 30105 | 无效 client_id |
| 30106 | 无效 access_token |
| 30107 | 无效 client_token |
| 30108 | Access-Token 不具备指定的 Scope |
| 30109 | Client-Token 不具备指定的 Scope |
| 30110 | 无效 code 码 |
| 30111 | 无效 Refresh-Token |
| 30112 | 请求的 Scope 暂未签约 |
| 30113 | 无效 redirect_url |
| 30114 | 非法 redirect_url |
| 30115 | 无效 client_secret |
| 30120 | redirect_uri 不一致 |
| 30122 | client_id 不一致 |
| 30125 | 无效 response_type |
| 30126 | 无效 grant_type |
| 30127 | 无效 state |
| 30141 | 系统暂未开放的授权模式 |
| 30142 | 应用暂未开放的授权模式 |
| 30151 | 无效的请求 Method |
| 30191 | 其它异常 |
#### sa-token-jwt 插件相关:

View File

@ -86,7 +86,7 @@ URL 没有通过校验,拒绝授权!
- 反例:`http://sa-oauth-client.com@sa-token.cc`
*详见源码:[SaOAuth2Template.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java)
`checkRightUrl` 方法。*
`checkRedirectUri` 方法。*
2、AllowUrls 配置的地址 `*` 通配符只允许出现在字符串末尾,不允许出现在字符串中间位置。

View File

@ -1,4 +1,4 @@
# OAuth2-自定义权限处理器
# OAuth2-自定义 Scope 权限处理器
---

View File

@ -44,12 +44,11 @@ public interface SaOAuth2DataConverter {
String convertScopeListToString(List<String> scopeList);
/**
* 转换 AllowUrl 数据格式String -> List
* @param allowUrl /
* 转换 redirect_uri 数据格式String -> List
* @param redirectUris /
* @return /
*/
List<String> convertAllowUrlStringToList(String allowUrl);
List<String> convertRedirectUriStringToList(String redirectUris);
/**
* Code 转换为 Access-Token

View File

@ -59,14 +59,14 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
}
/**
* 转换 AllowUrl 数据格式String -> List
* 转换 redirect_uri 数据格式String -> List
*/
@Override
public List<String> convertAllowUrlStringToList(String allowUrl) {
if(SaFoxUtil.isEmpty(allowUrl)) {
public List<String> convertRedirectUriStringToList(String redirectUris) {
if(SaFoxUtil.isEmpty(redirectUris)) {
return new ArrayList<>();
}
return SaFoxUtil.convertStringToList(allowUrl);
return SaFoxUtil.convertStringToList(redirectUris);
}
/**

View File

@ -26,7 +26,9 @@ import cn.dev33.satoken.oauth2.data.model.RefreshTokenModel;
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.SaOAuth2AuthorizationCodeException;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.oauth2.exception.SaOAuth2RefreshTokenException;
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
import cn.dev33.satoken.util.SaFoxUtil;
@ -79,7 +81,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
// 1先校验
CodeModel cm = dao.getCode(code);
SaOAuth2Exception.throwBy(cm == null, "无效code", SaOAuth2ErrorCode.CODE_30110);
SaOAuth2AuthorizationCodeException.throwBy(cm == null, "无效 code: " + code, code, SaOAuth2ErrorCode.CODE_30110);
// 2删除旧Token
dao.deleteAccessToken(dao.getAccessTokenValue(cm.clientId, cm.loginId));
@ -118,7 +120,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
// 获取 Refresh-Token 信息
RefreshTokenModel rt = dao.getRefreshToken(refreshToken);
SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken, SaOAuth2ErrorCode.CODE_30111);
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效 refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30111);
// 如果配置了[每次刷新产生新的Refresh-Token]
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(rt.clientId);
@ -276,7 +278,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
public void checkState(String state) {
String value = SaOAuth2Manager.getDao().getState(state);
if(SaFoxUtil.isNotEmpty(value)) {
throw new SaOAuth2Exception("多次请求的 state 不可重复: " + state);
throw new SaOAuth2Exception("多次请求的 state 不可重复: " + state).setCode(SaOAuth2ErrorCode.CODE_30127);
}
SaOAuth2Manager.getDao().saveState(state);
}

View File

@ -72,7 +72,7 @@ public interface SaOAuth2DataResolver {
* @param at token信息
* @return /
*/
Map<String, Object> buildTokenReturnValue(AccessTokenModel at);
Map<String, Object> buildAccessTokenReturnValue(AccessTokenModel at);
/**
* 构建返回值: RefreshToken 刷新 Access-Token
@ -80,7 +80,7 @@ public interface SaOAuth2DataResolver {
* @return /
*/
default Map<String, Object> buildRefreshTokenReturnValue(AccessTokenModel at) {
return buildTokenReturnValue(at);
return buildAccessTokenReturnValue(at);
}
/**

View File

@ -18,12 +18,13 @@ package cn.dev33.satoken.oauth2.data.resolver;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.Param;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.TokenType;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
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.util.SaFoxUtil;
import cn.dev33.satoken.util.SaResult;
@ -50,8 +51,8 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
@Override
public ClientIdAndSecretModel readClientIdAndSecret(SaRequest request) {
// 优先从请求参数中获取
String clientId = request.getParam(SaOAuth2Consts.Param.client_id);
String clientSecret = request.getParam(SaOAuth2Consts.Param.client_secret);
String clientId = request.getParam(Param.client_id);
String clientSecret = request.getParam(Param.client_secret);
if(SaFoxUtil.isNotEmpty(clientId)) {
return new ClientIdAndSecretModel(clientId, clientSecret);
}
@ -68,22 +69,22 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
}
// 如果都没有提供则抛出异常
throw new SaOAuth2Exception("请提供 client 信息");
throw new SaOAuth2Exception("请提供 client 信息").setCode(SaOAuth2ErrorCode.CODE_30191);
}
/**
* 数据读取从请求对象中读取 AccessToken
* 数据读取从请求对象中读取 AccessToken获取不到返回 null
*/
@Override
public String readAccessToken(SaRequest request) {
// 优先从请求参数中获取
String accessToken = request.getParam(SaOAuth2Consts.Param.access_token);
String accessToken = request.getParam(Param.access_token);
if(SaFoxUtil.isNotEmpty(accessToken)) {
return accessToken;
}
// 如果请求参数中没有提供 access_token 参数则尝试从 Authorization 中获取
String authorizationValue = request.getHeader(SaOAuth2Consts.Param.Authorization);
String authorizationValue = request.getHeader(Param.Authorization);
if(SaFoxUtil.isEmpty(authorizationValue)) {
return null;
}
@ -99,18 +100,18 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
}
/**
* 数据读取从请求对象中读取 ClientToken
* 数据读取从请求对象中读取 ClientToken获取不到返回 null
*/
@Override
public String readClientToken(SaRequest request) {
// 优先从请求参数中获取
String clientToken = request.getParam(SaOAuth2Consts.Param.client_token);
String clientToken = request.getParam(Param.client_token);
if(SaFoxUtil.isNotEmpty(clientToken)) {
return clientToken;
}
// 如果请求参数中没有提供 client_token 参数则尝试从 Authorization 中获取
String authorizationValue = request.getHeader(SaOAuth2Consts.Param.Authorization);
String authorizationValue = request.getHeader(Param.Authorization);
if(SaFoxUtil.isEmpty(authorizationValue)) {
return null;
}
@ -131,13 +132,11 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
@Override
public RequestAuthModel readRequestAuthModel(SaRequest req, Object loginId) {
RequestAuthModel ra = new RequestAuthModel();
ra.clientId = req.getParamNotNull(SaOAuth2Consts.Param.client_id);
ra.responseType = req.getParamNotNull(SaOAuth2Consts.Param.response_type);
ra.redirectUri = req.getParamNotNull(SaOAuth2Consts.Param.redirect_uri);
ra.state = req.getParam(SaOAuth2Consts.Param.state);
// 数据解析
String scope = req.getParam(SaOAuth2Consts.Param.scope, "");
ra.scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(scope);
ra.clientId = req.getParamNotNull(Param.client_id);
ra.responseType = req.getParamNotNull(Param.response_type);
ra.redirectUri = req.getParamNotNull(Param.redirect_uri);
ra.state = req.getParam(Param.state);
ra.scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(req.getParam(Param.scope));
ra.loginId = loginId;
return ra;
}
@ -147,7 +146,7 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
* 构建返回值: 获取 token
*/
@Override
public Map<String, Object> buildTokenReturnValue(AccessTokenModel at) {
public Map<String, Object> buildAccessTokenReturnValue(AccessTokenModel at) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("token_type", at.tokenType);
map.put("access_token", at.accessToken);
@ -172,7 +171,6 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
Map<String, Object> map = new LinkedHashMap<>();
map.put("token_type", ct.tokenType);
map.put("client_token", ct.clientToken);
// 兼容 OAuth2 协议
if(SaOAuth2Manager.getServerConfig().mode4ReturnAccessToken) {
map.put("access_token", ct.clientToken);
}

View File

@ -35,10 +35,10 @@ public interface SaOAuth2ErrorCode {
/** LoginId 不可为空 */
int CODE_30104 = 30104;
/** 无效client_id */
/** 无效 client_id */
int CODE_30105 = 30105;
/** 无效access_token */
/** 无效 access_token */
int CODE_30106 = 30106;
/** 无效 client_token */
@ -50,57 +50,39 @@ public interface SaOAuth2ErrorCode {
/** Client-Token 不具备指定的 Scope */
int CODE_30109 = 30109;
/** 无效 code 码 */
/** 无效 Code 码 */
int CODE_30110 = 30110;
/** 无效 Refresh-Token */
int CODE_30111 = 30111;
/** 请求的Scope暂未签约 */
/** 请求的 Scope 暂未签约 */
int CODE_30112 = 30112;
/** 无效redirect_url */
/** 无效 redirect_url */
int CODE_30113 = 30113;
/** 非法redirect_url */
/** 非法 redirect_url */
int CODE_30114 = 30114;
/** 无效client_secret */
int CODE_30115 = 30115;
/** 请求的Scope暂未签约 */
int CODE_30116 = 30116;
/** 无效code */
int CODE_30117 = 30117;
/** 无效client_id */
int CODE_30118 = 30118;
/** 无效client_secret */
int CODE_30119 = 30119;
/** 无效redirect_uri */
/** redirect_uri 不一致 */
int CODE_30120 = 30120;
/** 无效refresh_token */
int CODE_30121 = 30121;
/** 无效client_id */
/** client_id 不一致 */
int CODE_30122 = 30122;
/** 无效client_secret */
int CODE_30123 = 30123;
/** 无效client_id */
int CODE_30124 = 30124;
/** 无效response_type */
/** 无效 response_type */
int CODE_30125 = 30125;
/** 无效grant_type */
/** 无效 grant_type */
int CODE_30126 = 30126;
/** 无效 state */
int CODE_30127 = 30127;
/** 暂未开放授权码模式 */
int CODE_30131 = 30131;
@ -113,7 +95,16 @@ public interface SaOAuth2ErrorCode {
/** 暂未开放凭证式模式 */
int CODE_30134 = 30134;
/** 无效的请求 Method */
/** 系统暂未开放的授权模式 */
int CODE_30141 = 30141;
/** 应用暂未开放的授权模式 */
int CODE_30142 = 30142;
/** 无效的请求 Method */
int CODE_30151 = 30151;
/** 其它异常 */
int CODE_30191 = 30191;
}

View File

@ -0,0 +1,74 @@
/*
* 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.exception;
/**
* 一个异常代表 Code 授权码相关错误
*
* @author click33
* @since 1.39.0
*/
public class SaOAuth2AuthorizationCodeException extends SaOAuth2Exception {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130114L;
/**
* 一个异常代表 Access-Token 相关错误
* @param cause 根异常原因
*/
public SaOAuth2AuthorizationCodeException(Throwable cause) {
super(cause);
}
/**
* 一个异常代表 Access-Token 相关错误
* @param message 异常描述
*/
public SaOAuth2AuthorizationCodeException(String message) {
super(message);
}
/**
* 具体引起异常的 code
*/
public String authorizationCode;
public String getAuthorizationCode() {
return authorizationCode;
}
public SaOAuth2AuthorizationCodeException setAuthorizationCode(String authorizationCode) {
this.authorizationCode = authorizationCode;
return this;
}
/**
* 如果 flag==true则抛出 message 异常
* @param flag 标记
* @param message 异常信息
* @param authorizationCode 引入异常的 code
* @param code 异常细分码
*/
public static void throwBy(boolean flag, String message, String authorizationCode, int code) {
if(flag) {
throw new SaOAuth2AuthorizationCodeException(message).setAuthorizationCode(authorizationCode).setCode(code);
}
}
}

View File

@ -22,7 +22,8 @@ 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 cn.dev33.satoken.oauth2.exception.SaOAuth2ClientModelException;
import cn.dev33.satoken.oauth2.exception.SaOAuth2RefreshTokenException;
import java.util.List;
@ -46,10 +47,10 @@ public class RefreshTokenGrantTypeHandler implements SaOAuth2GrantTypeHandlerInt
// 校验Refresh-Token 是否存在
RefreshTokenModel rt = SaOAuth2Manager.getDao().getRefreshToken(refreshToken);
SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken, SaOAuth2ErrorCode.CODE_30121);
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30111);
// 校验Refresh-Token 代表的 ClientId 与提供的 ClientId 是否一致
SaOAuth2Exception.throwBy( ! rt.clientId.equals(clientId), "无效client_id: " + clientId, SaOAuth2ErrorCode.CODE_30122);
SaOAuth2ClientModelException.throwBy( ! rt.clientId.equals(clientId), "无效client_id: " + clientId, clientId, SaOAuth2ErrorCode.CODE_30122);
// 获取新 Access-Token
AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().refreshAccessToken(refreshToken);

View File

@ -157,7 +157,7 @@ public class SaOAuth2ServerProcessor {
}
// 默认返回
throw new SaOAuth2Exception("无效response_type: " + ra.responseType).setCode(SaOAuth2ErrorCode.CODE_30125);
throw new SaOAuth2Exception("无效 response_type: " + ra.responseType).setCode(SaOAuth2ErrorCode.CODE_30125);
}
/**
@ -166,7 +166,7 @@ public class SaOAuth2ServerProcessor {
*/
public Object token() {
AccessTokenModel accessTokenModel = SaOAuth2Strategy.instance.grantTypeAuth.apply(SaHolder.getRequest());
return SaOAuth2Manager.getDataResolver().buildTokenReturnValue(accessTokenModel);
return SaOAuth2Manager.getDataResolver().buildAccessTokenReturnValue(accessTokenModel);
}
/**
@ -239,7 +239,7 @@ public class SaOAuth2ServerProcessor {
// 此请求只允许 POST 方式
if(!req.isMethod(SaHttpMethod.POST)) {
throw new SaOAuth2Exception("无效请求方式:" + req.getMethod()).setCode(SaOAuth2ErrorCode.CODE_30141);
throw new SaOAuth2Exception("无效请求方式:" + req.getMethod()).setCode(SaOAuth2ErrorCode.CODE_30151);
}
// 确认授权
@ -366,7 +366,7 @@ public class SaOAuth2ServerProcessor {
}
// 其它
else {
throw new SaOAuth2Exception("无效 response_type: " + req.getParam(Param.response_type)).setCode(SaOAuth2ErrorCode.CODE_30125);
throw new SaOAuth2Exception("无效 response_type: " + responseType).setCode(SaOAuth2ErrorCode.CODE_30125);
}
}
@ -374,14 +374,14 @@ public class SaOAuth2ServerProcessor {
* 系统未开放此授权模式时抛出异常
*/
public void throwErrorSystemNotEnableModel() {
throw new SaOAuth2Exception("系统暂未开放此授权模式").setCode(SaOAuth2ErrorCode.CODE_30131);
throw new SaOAuth2Exception("系统暂未开放此授权模式").setCode(SaOAuth2ErrorCode.CODE_30141);
}
/**
* 应用未开放此授权模式时抛出异常
*/
public void throwErrorClientNotEnableModel() {
throw new SaOAuth2Exception("应用暂未开放此授权模式").setCode(SaOAuth2ErrorCode.CODE_30131);
throw new SaOAuth2Exception("应用暂未开放此授权模式").setCode(SaOAuth2ErrorCode.CODE_30142);
}
}

View File

@ -22,6 +22,7 @@ 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.error.SaOAuth2ErrorCode;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.oauth2.function.strategy.*;
import cn.dev33.satoken.oauth2.granttype.handler.AuthorizationCodeGrantTypeHandler;
@ -162,16 +163,16 @@ public final class SaOAuth2Strategy {
String grantType = req.getParamNotNull(SaOAuth2Consts.Param.grant_type);
SaOAuth2GrantTypeHandlerInterface grantTypeHandler = grantTypeHandlerMap.get(grantType);
if(grantTypeHandler == null) {
throw new RuntimeException("无效 grant_type: " + grantType);
throw new SaOAuth2Exception("无效 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
}
// 看看全局是否开启了此 grantType
SaOAuth2ServerConfig config = SaOAuth2Manager.getServerConfig();
if(grantType.equals(GrantType.authorization_code) && !config.getEnableAuthorizationCode() ) {
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType);
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
}
if(grantType.equals(GrantType.password) && !config.getEnablePassword() ) {
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType);
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
}
// 校验 clientSecret scope
@ -181,7 +182,7 @@ public final class SaOAuth2Strategy {
// 检测应用是否开启此 grantType
if(!clientModel.getAllowGrantTypes().contains(grantType)) {
throw new SaOAuth2Exception("应用未开放的 grant_type: " + grantType);
throw new SaOAuth2Exception("应用未开放的 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30141);
}
// 调用 处理器

View File

@ -72,8 +72,11 @@ public class SaOAuth2Template {
*/
public SaClientModel checkClientSecret(String clientId, String clientSecret) {
SaClientModel cm = checkClientModel(clientId);
SaOAuth2ClientModelException.throwBy(cm.clientSecret == null || ! cm.clientSecret.equals(clientSecret), "无效client_secret: " + clientSecret,
clientId, SaOAuth2ErrorCode.CODE_30115);
if(cm.clientSecret == null || ! cm.clientSecret.equals(clientSecret)) {
throw new SaOAuth2ClientModelException("无效 client_secret: " + clientSecret)
.setClientId(clientId)
.setCode(SaOAuth2ErrorCode.CODE_30115);
}
return cm;
}
@ -146,7 +149,7 @@ public class SaOAuth2Template {
public void checkRedirectUri(String clientId, String url) {
// 1是否是一个有效的url
if( ! SaFoxUtil.isUrl(url)) {
throw new SaOAuth2ClientModelException("无效redirect_url" + url)
throw new SaOAuth2ClientModelException("无效 redirect_url" + url)
.setClientId(clientId)
.setCode(SaOAuth2ErrorCode.CODE_30113);
}
@ -180,7 +183,8 @@ public class SaOAuth2Template {
//
// 但是为了安全起见这么做还是有必要的
throw new SaOAuth2ClientModelException("无效 redirect_url不允许出现@字符):" + url)
.setClientId(clientId);
.setClientId(clientId)
.setCode(SaOAuth2ErrorCode.CODE_30113);
}
// 4是否在[允许地址列表]之中
@ -231,7 +235,8 @@ public class SaOAuth2Template {
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://shop.sa-oauth2-client.com/
//
// 但是为了安全起见这么做还是有必要的
throw new SaOAuth2Exception("无效的 allow-url 配置(*通配符只允许出现在最后一位):" + url);
throw new SaOAuth2Exception("无效的 allow-url 配置(*通配符只允许出现在最后一位):" + url)
.setCode(SaOAuth2ErrorCode.CODE_30114);
}
}
}
@ -299,18 +304,18 @@ public class SaOAuth2Template {
// 校验Code是否存在
CodeModel cm = dao.getCode(code);
SaOAuth2Exception.throwBy(cm == null, "无效 code: " + code, SaOAuth2ErrorCode.CODE_30117);
SaOAuth2AuthorizationCodeException.throwBy(cm == null, "无效 code: " + code, code, SaOAuth2ErrorCode.CODE_30110);
// 校验ClientId是否一致
SaOAuth2Exception.throwBy( ! cm.clientId.equals(clientId), "无效 client_id: " + clientId, SaOAuth2ErrorCode.CODE_30118);
SaOAuth2ClientModelException.throwBy( ! cm.clientId.equals(clientId), "无效 client_id: " + clientId, clientId, SaOAuth2ErrorCode.CODE_30105);
// 校验Secret是否正确
String dbSecret = checkClientModel(clientId).clientSecret;
SaOAuth2Exception.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效 client_secret: " + clientSecret, SaOAuth2ErrorCode.CODE_30119);
SaOAuth2ClientModelException.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效 client_secret: " + clientSecret, clientId, SaOAuth2ErrorCode.CODE_30115);
// 如果提供了redirectUri则校验其是否与请求Code时提供的一致
if( ! SaFoxUtil.isEmpty(redirectUri)) {
SaOAuth2Exception.throwBy( ! redirectUri.equals(cm.redirectUri), "无效 redirect_uri: " + redirectUri, SaOAuth2ErrorCode.CODE_30120);
SaOAuth2ClientModelException.throwBy( ! redirectUri.equals(cm.redirectUri), "无效 redirect_uri: " + redirectUri, clientId, SaOAuth2ErrorCode.CODE_30120);
}
// 返回CodeModel
@ -330,15 +335,15 @@ public class SaOAuth2Template {
// 校验Refresh-Token是否存在
RefreshTokenModel rt = dao.getRefreshToken(refreshToken);
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效 refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30121);
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效 refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30111);
// 校验ClientId是否一致
SaOAuth2ClientModelException.throwBy( ! rt.clientId.equals(clientId), "无效 client_id: " + clientId, clientId, SaOAuth2ErrorCode.CODE_30122);
// 校验Secret是否正确
String dbSecret = checkClientModel(clientId).clientSecret;
SaOAuth2ClientModelException.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效client_secret: " + clientSecret,
clientId, SaOAuth2ErrorCode.CODE_30123);
SaOAuth2ClientModelException.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效 client_secret: " + clientSecret,
clientId, SaOAuth2ErrorCode.CODE_30115);
// 返回 Refresh-Token
return rt;
@ -353,7 +358,7 @@ public class SaOAuth2Template {
*/
public AccessTokenModel checkAccessTokenParam(String clientId, String clientSecret, String accessToken) {
AccessTokenModel at = checkAccessToken(accessToken);
SaOAuth2ClientModelException.throwBy( ! at.clientId.equals(clientId), "无效 client_id" + clientId, clientId, SaOAuth2ErrorCode.CODE_30124);
SaOAuth2ClientModelException.throwBy( ! at.clientId.equals(clientId), "无效 client_id" + clientId, clientId, SaOAuth2ErrorCode.CODE_30122);
checkClientSecret(clientId, clientSecret);
return at;
}