mirror of
https://gitee.com/dromara/sa-token.git
synced 2024-12-01 19:37:42 +08:00
优化 sa-token-oauth2 异常细分状态码
This commit is contained in:
parent
ffd557c5d7
commit
b552dd334c
@ -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)
|
||||
|
@ -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、用户授权记录
|
||||
|
@ -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 插件相关:
|
||||
|
@ -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 配置的地址 `*` 通配符只允许出现在字符串末尾,不允许出现在字符串中间位置。
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# OAuth2-自定义权限处理器
|
||||
# OAuth2-自定义 Scope 权限及处理器
|
||||
|
||||
---
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// 调用 处理器
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user