mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-10-15 18:54:54 +08:00
完善 SaOAuth2Util 相关方法
This commit is contained in:
@@ -85,12 +85,6 @@ public interface SaOAuth2DataGenerate {
|
||||
*/
|
||||
String buildImplicitRedirectUri(String redirectUri, String token, String state);
|
||||
|
||||
/**
|
||||
* 回收 Access-Token
|
||||
* @param accessToken Access-Token值
|
||||
*/
|
||||
void revokeAccessToken(String accessToken);
|
||||
|
||||
/**
|
||||
* 检查 state 是否被重复使用
|
||||
* @param state /
|
||||
|
@@ -126,7 +126,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
// 删除旧 Refresh-Token
|
||||
dao.deleteRefreshToken(rt.refreshToken);
|
||||
|
||||
// 创建并保持新的 Refresh-Token
|
||||
// 创建并保存新的 Refresh-Token
|
||||
rt = SaOAuth2Manager.getDataConverter().convertRefreshTokenToRefreshToken(rt);
|
||||
dao.saveRefreshToken(rt);
|
||||
dao.saveRefreshTokenIndex(rt);
|
||||
@@ -268,31 +268,6 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 Access-Token
|
||||
* @param accessToken Access-Token值
|
||||
*/
|
||||
@Override
|
||||
public void revokeAccessToken(String accessToken) {
|
||||
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
|
||||
// 如果查不到任何东西, 直接返回
|
||||
AccessTokenModel at = dao.getAccessToken(accessToken);
|
||||
if(at == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 删除 Access-Token
|
||||
dao.deleteAccessToken(accessToken);
|
||||
dao.deleteAccessTokenIndex(at.clientId, at.loginId);
|
||||
|
||||
// 删除对应的 Refresh-Token
|
||||
String refreshToken = dao.getRefreshTokenValue(at.clientId, at.loginId);
|
||||
dao.deleteRefreshToken(refreshToken);
|
||||
dao.deleteRefreshTokenIndex(at.clientId, at.loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 state 是否被重复使用
|
||||
* @param state /
|
||||
|
@@ -17,7 +17,8 @@ package cn.dev33.satoken.oauth2.data.loader;
|
||||
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
|
||||
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
|
||||
import cn.dev33.satoken.oauth2.exception.SaOAuth2ClientModelException;
|
||||
import cn.dev33.satoken.secure.SaSecureUtil;
|
||||
|
||||
/**
|
||||
@@ -47,7 +48,9 @@ public interface SaOAuth2DataLoader {
|
||||
default SaClientModel getClientModelNotNull(String clientId) {
|
||||
SaClientModel clientModel = getClientModel(clientId);
|
||||
if(clientModel == null) {
|
||||
throw new SaOAuth2Exception("未找到对应的 Client 信息");
|
||||
throw new SaOAuth2ClientModelException("无效 client_id: " + clientId)
|
||||
.setClientId(clientId)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30105);
|
||||
}
|
||||
return clientModel;
|
||||
}
|
||||
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Access-Token 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2AccessTokenException extends SaOAuth2Exception {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Access-Token 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2AccessTokenException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Access-Token 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2AccessTokenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 Access-Token 值
|
||||
*/
|
||||
public String accessToken;
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public SaOAuth2AccessTokenException setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2AccessTokenException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Access-Token Scope 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2AccessTokenScopeException extends SaOAuth2AccessTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Access-Token Scope 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2AccessTokenScopeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Access-Token Scope 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2AccessTokenScopeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 Access-Token 值
|
||||
*/
|
||||
public String accessToken;
|
||||
|
||||
/**
|
||||
* 具体引起异常的 scope 值
|
||||
*/
|
||||
public String scope;
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public SaOAuth2AccessTokenScopeException setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public SaOAuth2AccessTokenScopeException setScope(String scope) {
|
||||
this.scope = scope;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2AccessTokenScopeException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ClientModel 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2ClientModelException extends SaOAuth2Exception {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ClientModel 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2ClientModelException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ClientModel 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2ClientModelException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 ClientId 值
|
||||
*/
|
||||
public String clientId;
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public SaOAuth2ClientModelException setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2ClientModelException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param clientId 应用id
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, String clientId, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2ClientModelException(message).setClientId(clientId).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ClientModel Scope 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2ClientModelScopeException extends SaOAuth2ClientModelException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ClientModel Scope 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2ClientModelScopeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 ClientModel Scope 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2ClientModelScopeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 ClientId 值
|
||||
*/
|
||||
public String clientId;
|
||||
|
||||
/**
|
||||
* 具体引起异常的 scope 值
|
||||
*/
|
||||
public String scope;
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public SaOAuth2ClientModelScopeException setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public SaOAuth2ClientModelScopeException setScope(String scope) {
|
||||
this.scope = scope;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2ClientModelScopeException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Client-Token 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2ClientTokenException extends SaOAuth2Exception {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Client-Token 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2ClientTokenException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Client-Token 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2ClientTokenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 Client-Token 值
|
||||
*/
|
||||
public String clientToken;
|
||||
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
public SaOAuth2ClientTokenException setClientToken(String clientToken) {
|
||||
this.clientToken = clientToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2ClientTokenException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Client-Token Scope 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2ClientTokenScopeException extends SaOAuth2ClientTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Client-Token Scope 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2ClientTokenScopeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Client-Token Scope 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2ClientTokenScopeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 Client-Token 值
|
||||
*/
|
||||
public String clientToken;
|
||||
|
||||
/**
|
||||
* 具体引起异常的 scope 值
|
||||
*/
|
||||
public String scope;
|
||||
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
public SaOAuth2ClientTokenScopeException setClientToken(String clientToken) {
|
||||
this.clientToken = clientToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public SaOAuth2ClientTokenScopeException setScope(String scope) {
|
||||
this.scope = scope;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2ClientTokenScopeException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -18,7 +18,7 @@ package cn.dev33.satoken.oauth2.exception;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* 一个异常:代表OAuth2认证流程错误
|
||||
* 一个异常:代表 OAuth2 认证流程错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.33.0
|
||||
@@ -31,7 +31,7 @@ public class SaOAuth2Exception extends SaTokenException {
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表OAuth2认证流程错误
|
||||
* 一个异常:代表 OAuth2 认证流程错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2Exception(Throwable cause) {
|
||||
@@ -39,7 +39,7 @@ public class SaOAuth2Exception extends SaTokenException {
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表OAuth2认证流程错误
|
||||
* 一个异常:代表 OAuth2 认证流程错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2Exception(String message) {
|
||||
@@ -47,7 +47,7 @@ public class SaOAuth2Exception extends SaTokenException {
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果flag==true,则抛出message异常
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Refresh-Token 相关错误
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class SaOAuth2RefreshTokenException extends SaOAuth2Exception {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130114L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Refresh-Token 相关错误
|
||||
* @param cause 根异常原因
|
||||
*/
|
||||
public SaOAuth2RefreshTokenException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个异常:代表 Refresh-Token 相关错误
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public SaOAuth2RefreshTokenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体引起异常的 Refresh-Token 值
|
||||
*/
|
||||
public String refreshToken;
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public SaOAuth2RefreshTokenException setRefreshToken(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2RefreshTokenException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 flag==true,则抛出 message 异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param refreshToken refreshToken
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message, String refreshToken, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2RefreshTokenException(message).setRefreshToken(refreshToken).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -37,6 +37,7 @@ 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.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
|
||||
import java.util.List;
|
||||
@@ -130,10 +131,10 @@ public class SaOAuth2ServerProcessor {
|
||||
RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, SaOAuth2Manager.getStpLogic().getLoginId());
|
||||
|
||||
// 4、校验:重定向域名是否合法
|
||||
oauth2Template.checkRightUrl(ra.clientId, ra.redirectUri);
|
||||
oauth2Template.checkRedirectUri(ra.clientId, ra.redirectUri);
|
||||
|
||||
// 5、校验:此次申请的Scope,该Client是否已经签约
|
||||
oauth2Template.checkContract(ra.clientId, ra.scopes);
|
||||
oauth2Template.checkContractScope(ra.clientId, ra.scopes);
|
||||
|
||||
// 6、判断:如果此次申请的Scope,该用户尚未授权,则转到授权页面
|
||||
boolean isNeedCarefulConfirm = oauth2Template.isNeedCarefulConfirm(ra.loginId, ra.clientId, ra.scopes);
|
||||
@@ -205,7 +206,7 @@ public class SaOAuth2ServerProcessor {
|
||||
oauth2Template.checkAccessTokenParam(clientId, clientSecret, accessToken);
|
||||
|
||||
// 回收 Access-Token
|
||||
SaOAuth2Manager.getDataGenerate().revokeAccessToken(accessToken);
|
||||
oauth2Template.revokeAccessToken(accessToken);
|
||||
|
||||
// 返回
|
||||
return SaOAuth2Manager.getDataResolver().buildRevokeTokenReturnValue();
|
||||
@@ -306,7 +307,7 @@ public class SaOAuth2ServerProcessor {
|
||||
List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(req.getParam(Param.scope));
|
||||
|
||||
//校验 ClientScope
|
||||
oauth2Template.checkContract(clientId, scopes);
|
||||
oauth2Template.checkContractScope(clientId, scopes);
|
||||
|
||||
// 校验 ClientSecret
|
||||
oauth2Template.checkClientSecret(clientId, clientSecret);
|
||||
|
@@ -23,11 +23,10 @@ import cn.dev33.satoken.oauth2.data.model.CodeModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.RefreshTokenModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
|
||||
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
|
||||
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
import cn.dev33.satoken.oauth2.exception.*;
|
||||
import cn.dev33.satoken.strategy.SaStrategy;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -38,91 +37,206 @@ import java.util.List;
|
||||
*/
|
||||
public class SaOAuth2Template {
|
||||
|
||||
// ------------------- 数据加载
|
||||
// ----------------- ClientModel 相关 -----------------
|
||||
|
||||
/**
|
||||
* 根据id获取Client信息
|
||||
* @param clientId 应用id
|
||||
* @return ClientModel
|
||||
* 获取 ClientModel,根据 clientId
|
||||
*
|
||||
* @param clientId /
|
||||
* @return /
|
||||
*/
|
||||
public SaClientModel getClientModel(String clientId) {
|
||||
return SaOAuth2Manager.getDataLoader().getClientModel(clientId);
|
||||
}
|
||||
|
||||
// ------------------- 资源校验API
|
||||
/**
|
||||
* 根据id获取Client信息, 如果Client为空,则抛出异常
|
||||
* @param clientId 应用id
|
||||
* @return ClientModel
|
||||
* 校验 clientId 信息并返回 ClientModel,如果找不到对应 Client 信息则抛出异常
|
||||
* @param clientId /
|
||||
* @return /
|
||||
*/
|
||||
public SaClientModel checkClientModel(String clientId) {
|
||||
SaClientModel clientModel = getClientModel(clientId);
|
||||
if(clientModel == null) {
|
||||
throw new SaOAuth2Exception("无效client_id: " + clientId).setCode(SaOAuth2ErrorCode.CODE_30105);
|
||||
throw new SaOAuth2ClientModelException("无效 client_id: " + clientId)
|
||||
.setClientId(clientId)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30105);
|
||||
}
|
||||
return clientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token,如果AccessToken为空则抛出异常
|
||||
* @param accessToken .
|
||||
* @return .
|
||||
* 校验:clientId 与 clientSecret 是否正确
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @return SaClientModel对象
|
||||
*/
|
||||
public AccessTokenModel checkAccessToken(String accessToken) {
|
||||
AccessTokenModel at = SaOAuth2Manager.getDao().getAccessToken(accessToken);
|
||||
SaOAuth2Exception.throwBy(at == null, "无效access_token:" + accessToken, SaOAuth2ErrorCode.CODE_30106);
|
||||
return at;
|
||||
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);
|
||||
return cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Client-Token,如果ClientToken为空则抛出异常
|
||||
* @param clientToken .
|
||||
* @return .
|
||||
* 校验:clientId 与 clientSecret 是否正确,并且是否签约了指定 scopes
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @param scopes 权限
|
||||
* @return SaClientModel对象
|
||||
*/
|
||||
public ClientTokenModel checkClientToken(String clientToken) {
|
||||
ClientTokenModel ct = SaOAuth2Manager.getDao().getClientToken(clientToken);
|
||||
SaOAuth2Exception.throwBy(ct == null, "无效:client_token" + clientToken, SaOAuth2ErrorCode.CODE_30107);
|
||||
return ct;
|
||||
public SaClientModel checkClientSecretAndScope(String clientId, String clientSecret, List<String> scopes) {
|
||||
SaClientModel cm = checkClientSecret(clientId, clientSecret);
|
||||
checkContractScope(cm, scopes);
|
||||
return cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token 所代表的LoginId
|
||||
* @param accessToken Access-Token
|
||||
* @return LoginId
|
||||
* 判断:该 Client 是否签约了指定的 Scope,返回 true 或 false
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限
|
||||
* @return /
|
||||
*/
|
||||
public Object getLoginIdByAccessToken(String accessToken) {
|
||||
return checkAccessToken(accessToken).loginId;
|
||||
}
|
||||
/**
|
||||
* 校验:指定 Access-Token 是否具有指定 Scope
|
||||
* @param accessToken Access-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public void checkScope(String accessToken, String... scopes) {
|
||||
if(scopes == null || scopes.length == 0) {
|
||||
return;
|
||||
}
|
||||
AccessTokenModel at = checkAccessToken(accessToken);
|
||||
List<String> scopeList = at.scopes;
|
||||
for (String scope : scopes) {
|
||||
SaOAuth2Exception.throwBy( ! scopeList.contains(scope), "该 Access-Token 不具备 Scope:" + scope, SaOAuth2ErrorCode.CODE_30108);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 校验:指定 Client-Token 是否具有指定 Scope
|
||||
* @param clientToken Client-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public void checkClientTokenScope(String clientToken, String... scopes) {
|
||||
if(scopes == null || scopes.length == 0) {
|
||||
return;
|
||||
}
|
||||
ClientTokenModel ct = checkClientToken(clientToken);
|
||||
List<String> scopeList = ct.scopes;
|
||||
for (String scope : scopes) {
|
||||
SaOAuth2Exception.throwBy( ! scopeList.contains(scope), "该 Client-Token 不具备 Scope:" + scope, SaOAuth2ErrorCode.CODE_30109);
|
||||
public boolean isContractScope(String clientId, List<String> scopes) {
|
||||
try {
|
||||
checkContractScope(clientId, scopes);
|
||||
return true;
|
||||
} catch (SaOAuth2ClientModelException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:该 Client 是否签约了指定的 Scope,如果没有则抛出异常
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限列表
|
||||
* @return /
|
||||
*/
|
||||
public SaClientModel checkContractScope(String clientId, List<String> scopes) {
|
||||
return checkContractScope(checkClientModel(clientId), scopes);
|
||||
}
|
||||
|
||||
// ------------------- check 数据校验
|
||||
/**
|
||||
* 校验:该 Client 是否签约了指定的 Scope,如果没有则抛出异常
|
||||
* @param cm 应用
|
||||
* @param scopes 权限列表
|
||||
* @return /
|
||||
*/
|
||||
public SaClientModel checkContractScope(SaClientModel cm, List<String> scopes) {
|
||||
if(SaFoxUtil.isEmptyList(scopes)) {
|
||||
return cm;
|
||||
}
|
||||
for (String scope : scopes) {
|
||||
if(! cm.contractScopes.contains(scope)) {
|
||||
throw new SaOAuth2ClientModelScopeException("该 client 暂未签约 scope: " + scope)
|
||||
.setClientId(cm.clientId)
|
||||
.setScope(scope)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30112);
|
||||
}
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
|
||||
// --------- redirect_uri 相关
|
||||
|
||||
/**
|
||||
* 校验:该 Client 使用指定 url 作为回调地址,是否合法
|
||||
* @param clientId 应用id
|
||||
* @param url 指定url
|
||||
*/
|
||||
public void checkRedirectUri(String clientId, String url) {
|
||||
// 1、是否是一个有效的url
|
||||
if( ! SaFoxUtil.isUrl(url)) {
|
||||
throw new SaOAuth2ClientModelException("无效redirect_url:" + url)
|
||||
.setClientId(clientId)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30113);
|
||||
}
|
||||
|
||||
// 2、截取掉?后面的部分
|
||||
int qIndex = url.indexOf("?");
|
||||
if(qIndex != -1) {
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
|
||||
// 3、不允许出现@字符
|
||||
if(url.contains("@")) {
|
||||
// 为什么不允许出现 @ 字符呢,因为这有可能导致 redirect_url 参数绕过 AllowUrl 列表的校验
|
||||
//
|
||||
// 举个例子 SaClientModel 配置:
|
||||
// allow-url=http://sa-oauth-client.com*
|
||||
//
|
||||
// 开发者原意是为了允许 sa-oauth-client.com 下的所有地址都可以下放 code
|
||||
//
|
||||
// 但是如果攻击者精心构建一个url:
|
||||
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com@sa-token.cc
|
||||
//
|
||||
// 那么这个url就会绕过 allow-url 的校验,code 被下发到了第三方服务器地址:
|
||||
// http://sa-token.cc/?code=i8vDfbpqBViMe01QoLY1kHROJWYvv9plBtvTZ6kk77KK0e0U4Xj99NPfSZEYjRul
|
||||
//
|
||||
// 造成了 code 参数劫持
|
||||
// 所以此处需要禁止在 url 中出现 @ 字符
|
||||
//
|
||||
// 这么一刀切的做法,可能会导致一些特殊的正常url也无法通过校验,例如:
|
||||
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com/@getInfo
|
||||
//
|
||||
// 但是为了安全起见,这么做还是有必要的
|
||||
throw new SaOAuth2ClientModelException("无效 redirect_url(不允许出现@字符):" + url)
|
||||
.setClientId(clientId);
|
||||
}
|
||||
|
||||
// 4、是否在[允许地址列表]之中
|
||||
SaClientModel clientModel = checkClientModel(clientId);
|
||||
checkRedirectUriListNormal(clientModel.allowRedirectUris);
|
||||
if( ! SaStrategy.instance.hasElement.apply(clientModel.allowRedirectUris, url)) {
|
||||
throw new SaOAuth2ClientModelException("非法 redirect_url: " + url)
|
||||
.setClientId(clientId)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30114);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验配置的 allowRedirectUris 是否合规,如果不合规则抛出异常
|
||||
* @param redirectUriList 待校验的 allow-url 地址列表
|
||||
*/
|
||||
public void checkRedirectUriListNormal(List<String> redirectUriList){
|
||||
checkRedirectUriListNormalStaticMethod(redirectUriList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验配置的 allowRedirectUris 是否合规,如果不合规则抛出异常,静态方法内部实现
|
||||
* @param redirectUriList 待校验的 allow-url 地址列表
|
||||
*/
|
||||
public static void checkRedirectUriListNormalStaticMethod(List<String> redirectUriList){
|
||||
for (String url : redirectUriList) {
|
||||
int index = url.indexOf("*");
|
||||
// 如果配置了 * 字符,则必须出现在最后一位,否则属于无效配置项
|
||||
if(index != -1 && index != url.length() - 1) {
|
||||
// 为什么不允许 * 字符出现在中间位置呢,因为这有可能导致 redirect 参数绕过 allow-url 列表的校验
|
||||
//
|
||||
// 举个例子 SaClientModel 配置:
|
||||
// allow-url=http://*.sa-oauth-client.com/
|
||||
//
|
||||
// 开发者原意是为了允许 sa-oauth-client.com 下的所有子域名都可以下放 ticket
|
||||
// 例如:http://shop.sa-oauth-client.com/
|
||||
//
|
||||
// 但是如果攻击者精心构建一个url:
|
||||
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-token.cc/a.sa-oauth-client.com/
|
||||
//
|
||||
// 那么这个 url 就会绕过 allow-url 的校验,ticket 被下发到了第三方服务器地址:
|
||||
// http://sa-token.cc/a.sa-oauth-client.com/?code=v2KKMUFK7dDsMMzXLQ3aWGsyGUjrA0dBB2jeOWrpCnC8b5ScmXXQSv20mIwPK7Cx
|
||||
//
|
||||
// 造成了 ticket 参数劫持
|
||||
// 所以此处需要禁止 allow-url 配置项的中间位置出现 * 字符(出现在末尾是没有问题的)
|
||||
//
|
||||
// 这么一刀切的做法,可能会导致正常场景下的子域名url也无法通过校验,例如:
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------- 授权相关
|
||||
|
||||
/**
|
||||
* 判断:指定 loginId 是否对一个 Client 授权给了指定 Scope
|
||||
@@ -131,10 +245,9 @@ public class SaOAuth2Template {
|
||||
* @param scopes 权限
|
||||
* @return 是否已经授权
|
||||
*/
|
||||
public boolean isGrant(Object loginId, String clientId, List<String> scopes) {
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
List<String> grantScopeList = dao.getGrantScope(clientId, loginId);
|
||||
return scopes.isEmpty() || new HashSet<>(grantScopeList).containsAll(scopes);
|
||||
public boolean isGrantScope(Object loginId, String clientId, List<String> scopes) {
|
||||
List<String> grantScopeList = SaOAuth2Manager.getDao().getGrantScope(clientId, loginId);
|
||||
return SaFoxUtil.list1ContainList2AllElement(grantScopeList, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,143 +279,12 @@ public class SaOAuth2Template {
|
||||
}
|
||||
|
||||
// 根据近期授权记录,判断是否需要确认
|
||||
return !isGrant(loginId, clientId, scopes);
|
||||
return !isGrantScope(loginId, clientId, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:该Client是否签约了指定的Scope
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限(多个用逗号隔开)
|
||||
*/
|
||||
public void checkContract(String clientId, List<String> scopes) {
|
||||
List<String> clientScopeList = checkClientModel(clientId).contractScopes;
|
||||
if( ! new HashSet<>(clientScopeList).containsAll(scopes)) {
|
||||
throw new SaOAuth2Exception("请求的Scope暂未签约").setCode(SaOAuth2ErrorCode.CODE_30112);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 校验:该Client使用指定url作为回调地址,是否合法
|
||||
* @param clientId 应用id
|
||||
* @param url 指定url
|
||||
*/
|
||||
public void checkRightUrl(String clientId, String url) {
|
||||
// 1、是否是一个有效的url
|
||||
if( ! SaFoxUtil.isUrl(url)) {
|
||||
throw new SaOAuth2Exception("无效redirect_url:" + url).setCode(SaOAuth2ErrorCode.CODE_30113);
|
||||
}
|
||||
|
||||
// 2、截取掉?后面的部分
|
||||
int qIndex = url.indexOf("?");
|
||||
if(qIndex != -1) {
|
||||
url = url.substring(0, qIndex);
|
||||
}
|
||||
// --------- 请求数据校验相关
|
||||
|
||||
// 3、不允许出现@字符
|
||||
if(url.contains("@")) {
|
||||
// 为什么不允许出现 @ 字符呢,因为这有可能导致 redirect_url 参数绕过 AllowUrl 列表的校验
|
||||
//
|
||||
// 举个例子 SaClientModel 配置:
|
||||
// allow-url=http://sa-oauth-client.com*
|
||||
//
|
||||
// 开发者原意是为了允许 sa-oauth-client.com 下的所有地址都可以下放 code
|
||||
//
|
||||
// 但是如果攻击者精心构建一个url:
|
||||
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com@sa-token.cc
|
||||
//
|
||||
// 那么这个url就会绕过 allow-url 的校验,code 被下发到了第三方服务器地址:
|
||||
// http://sa-token.cc/?code=i8vDfbpqBViMe01QoLY1kHROJWYvv9plBtvTZ6kk77KK0e0U4Xj99NPfSZEYjRul
|
||||
//
|
||||
// 造成了 code 参数劫持
|
||||
// 所以此处需要禁止在 url 中出现 @ 字符
|
||||
//
|
||||
// 这么一刀切的做法,可能会导致一些特殊的正常url也无法通过校验,例如:
|
||||
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com/@getInfo
|
||||
//
|
||||
// 但是为了安全起见,这么做还是有必要的
|
||||
throw new SaOAuth2Exception("无效 redirect_url(不允许出现@字符):" + url);
|
||||
}
|
||||
|
||||
// 4、是否在[允许地址列表]之中
|
||||
SaClientModel clientModel = checkClientModel(clientId);
|
||||
checkAllowUrlList(clientModel.allowRedirectUris);
|
||||
if( ! SaStrategy.instance.hasElement.apply(clientModel.allowRedirectUris, url)) {
|
||||
throw new SaOAuth2Exception("非法 redirect_url: " + url).setCode(SaOAuth2ErrorCode.CODE_30114);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验配置的 AllowUrl 是否合规,如果不合规则抛出异常
|
||||
* @param allowUrlList 待校验的 allow-url 地址列表
|
||||
*/
|
||||
public void checkAllowUrlList(List<String> allowUrlList){
|
||||
checkAllowUrlListStaticMethod(allowUrlList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验配置的 AllowUrl 是否合规,如果不合规则抛出异常
|
||||
* @param allowUrlList 待校验的 allow-url 地址列表
|
||||
*/
|
||||
public static void checkAllowUrlListStaticMethod(List<String> allowUrlList){
|
||||
for (String url : allowUrlList) {
|
||||
int index = url.indexOf("*");
|
||||
// 如果配置了 * 字符,则必须出现在最后一位,否则属于无效配置项
|
||||
if(index != -1 && index != url.length() - 1) {
|
||||
// 为什么不允许 * 字符出现在中间位置呢,因为这有可能导致 redirect 参数绕过 allow-url 列表的校验
|
||||
//
|
||||
// 举个例子 SaClientModel 配置:
|
||||
// allow-url=http://*.sa-oauth-client.com/
|
||||
//
|
||||
// 开发者原意是为了允许 sa-oauth-client.com 下的所有子域名都可以下放 ticket
|
||||
// 例如:http://shop.sa-oauth-client.com/
|
||||
//
|
||||
// 但是如果攻击者精心构建一个url:
|
||||
// http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-token.cc/a.sa-oauth-client.com/
|
||||
//
|
||||
// 那么这个 url 就会绕过 allow-url 的校验,ticket 被下发到了第三方服务器地址:
|
||||
// http://sa-token.cc/a.sa-oauth-client.com/?code=v2KKMUFK7dDsMMzXLQ3aWGsyGUjrA0dBB2jeOWrpCnC8b5ScmXXQSv20mIwPK7Cx
|
||||
//
|
||||
// 造成了 ticket 参数劫持
|
||||
// 所以此处需要禁止 allow-url 配置项的中间位置出现 * 字符(出现在末尾是没有问题的)
|
||||
//
|
||||
// 这么一刀切的做法,可能会导致正常场景下的子域名url也无法通过校验,例如:
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:clientId 与 clientSecret 是否正确
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @return SaClientModel对象
|
||||
*/
|
||||
public SaClientModel checkClientSecret(String clientId, String clientSecret) {
|
||||
SaClientModel cm = checkClientModel(clientId);
|
||||
SaOAuth2Exception.throwBy(cm.clientSecret == null || ! cm.clientSecret.equals(clientSecret),
|
||||
"无效client_secret: " + clientSecret, SaOAuth2ErrorCode.CODE_30115);
|
||||
return cm;
|
||||
}
|
||||
/**
|
||||
* 校验:clientId 与 clientSecret 是否正确,并且是否签约了指定 scopes
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @param scopes 权限
|
||||
* @return SaClientModel对象
|
||||
*/
|
||||
public SaClientModel checkClientSecretAndScope(String clientId, String clientSecret, List<String> scopes) {
|
||||
// 先校验 clientSecret
|
||||
SaClientModel cm = checkClientSecret(clientId, clientSecret);
|
||||
// 再校验 是否签约
|
||||
List<String> clientScopeList = cm.contractScopes;
|
||||
if( ! new HashSet<>(clientScopeList).containsAll(scopes)) {
|
||||
throw new SaOAuth2Exception("请求的Scope暂未签约").setCode(SaOAuth2ErrorCode.CODE_30116);
|
||||
}
|
||||
// 返回数据
|
||||
return cm;
|
||||
}
|
||||
/**
|
||||
* 校验:使用 code 获取 token 时提供的参数校验
|
||||
* @param code 授权码
|
||||
@@ -317,23 +299,24 @@ public class SaOAuth2Template {
|
||||
|
||||
// 校验:Code是否存在
|
||||
CodeModel cm = dao.getCode(code);
|
||||
SaOAuth2Exception.throwBy(cm == null, "无效code: " + code, SaOAuth2ErrorCode.CODE_30117);
|
||||
SaOAuth2Exception.throwBy(cm == null, "无效 code: " + code, SaOAuth2ErrorCode.CODE_30117);
|
||||
|
||||
// 校验:ClientId是否一致
|
||||
SaOAuth2Exception.throwBy( ! cm.clientId.equals(clientId), "无效client_id: " + clientId, SaOAuth2ErrorCode.CODE_30118);
|
||||
SaOAuth2Exception.throwBy( ! cm.clientId.equals(clientId), "无效 client_id: " + clientId, SaOAuth2ErrorCode.CODE_30118);
|
||||
|
||||
// 校验:Secret是否正确
|
||||
String dbSecret = checkClientModel(clientId).clientSecret;
|
||||
SaOAuth2Exception.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效client_secret: " + clientSecret, SaOAuth2ErrorCode.CODE_30119);
|
||||
SaOAuth2Exception.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效 client_secret: " + clientSecret, SaOAuth2ErrorCode.CODE_30119);
|
||||
|
||||
// 如果提供了redirectUri,则校验其是否与请求Code时提供的一致
|
||||
if( ! SaFoxUtil.isEmpty(redirectUri)) {
|
||||
SaOAuth2Exception.throwBy( ! redirectUri.equals(cm.redirectUri), "无效redirect_uri: " + redirectUri, SaOAuth2ErrorCode.CODE_30120);
|
||||
SaOAuth2Exception.throwBy( ! redirectUri.equals(cm.redirectUri), "无效 redirect_uri: " + redirectUri, SaOAuth2ErrorCode.CODE_30120);
|
||||
}
|
||||
|
||||
// 返回CodeModel
|
||||
return cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:使用 Refresh-Token 刷新 Access-Token 时提供的参数校验
|
||||
* @param clientId 应用id
|
||||
@@ -347,18 +330,20 @@ public class SaOAuth2Template {
|
||||
|
||||
// 校验:Refresh-Token是否存在
|
||||
RefreshTokenModel rt = dao.getRefreshToken(refreshToken);
|
||||
SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken, SaOAuth2ErrorCode.CODE_30121);
|
||||
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效 refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30121);
|
||||
|
||||
// 校验: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);
|
||||
|
||||
// 校验:Secret是否正确
|
||||
String dbSecret = checkClientModel(clientId).clientSecret;
|
||||
SaOAuth2Exception.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效client_secret: " + clientSecret, SaOAuth2ErrorCode.CODE_30123);
|
||||
SaOAuth2ClientModelException.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效client_secret: " + clientSecret,
|
||||
clientId, SaOAuth2ErrorCode.CODE_30123);
|
||||
|
||||
// 返回Refresh-Token
|
||||
// 返回 Refresh-Token
|
||||
return rt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:Access-Token、clientId、clientSecret 三者是否匹配成功
|
||||
* @param clientId 应用id
|
||||
@@ -368,30 +353,271 @@ public class SaOAuth2Template {
|
||||
*/
|
||||
public AccessTokenModel checkAccessTokenParam(String clientId, String clientSecret, String accessToken) {
|
||||
AccessTokenModel at = checkAccessToken(accessToken);
|
||||
SaOAuth2Exception.throwBy( ! at.clientId.equals(clientId), "无效client_id:" + clientId, SaOAuth2ErrorCode.CODE_30124);
|
||||
SaOAuth2ClientModelException.throwBy( ! at.clientId.equals(clientId), "无效 client_id:" + clientId, clientId, SaOAuth2ErrorCode.CODE_30124);
|
||||
checkClientSecret(clientId, clientSecret);
|
||||
return at;
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Access-Token 相关 -----------------
|
||||
|
||||
/**
|
||||
* 回收指定的 ClientToken
|
||||
* 获取 AccessTokenModel,无效的 AccessToken 会返回 null
|
||||
* @param accessToken /
|
||||
* @return /
|
||||
*/
|
||||
public AccessTokenModel getAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getDao().getAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Access-Token,成功返回 AccessTokenModel,失败则抛出异常
|
||||
* @param accessToken /
|
||||
* @return /
|
||||
*/
|
||||
public AccessTokenModel checkAccessToken(String accessToken) {
|
||||
AccessTokenModel at = SaOAuth2Manager.getDao().getAccessToken(accessToken);
|
||||
if(at == null) {
|
||||
throw new SaOAuth2AccessTokenException("无效 access_token: " + accessToken)
|
||||
.setAccessToken(accessToken)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30106);
|
||||
}
|
||||
return at;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token,根据索引: clientId、loginId
|
||||
* @param clientId /
|
||||
* @param loginId /
|
||||
* @return /
|
||||
*/
|
||||
public String getAccessTokenValue(String clientId, Object loginId) {
|
||||
return SaOAuth2Manager.getDao().getAccessTokenValue(clientId, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:指定 Access-Token 是否具有指定 Scope 列表,返回 true 或 false
|
||||
* @param accessToken Access-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public boolean hasAccessTokenScope(String accessToken, String... scopes) {
|
||||
try {
|
||||
checkAccessTokenScope(accessToken, scopes);
|
||||
return true;
|
||||
} catch (SaOAuth2AccessTokenException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定 Access-Token 是否具有指定 Scope 列表,如果不具备则抛出异常
|
||||
* @param accessToken Access-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public void checkAccessTokenScope(String accessToken, String... scopes) {
|
||||
if(SaFoxUtil.isEmptyArray(scopes)) {
|
||||
return;
|
||||
}
|
||||
ClientTokenModel ct = checkClientToken(accessToken);
|
||||
for (String scope : scopes) {
|
||||
if(! ct.scopes.contains(scope)) {
|
||||
throw new SaOAuth2AccessTokenScopeException("该 access_token 不具备 scope:" + scope)
|
||||
.setAccessToken(accessToken)
|
||||
.setScope(scope)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30108);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token 所代表的LoginId
|
||||
* @param accessToken Access-Token
|
||||
* @return LoginId
|
||||
*/
|
||||
public Object getLoginIdByAccessToken(String accessToken) {
|
||||
return checkAccessToken(accessToken).loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token 所代表的 clientId
|
||||
* @param accessToken Access-Token
|
||||
* @return LoginId
|
||||
*/
|
||||
public Object getClientIdByAccessToken(String accessToken) {
|
||||
return checkAccessToken(accessToken).clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 Access-Token
|
||||
* @param accessToken Access-Token值
|
||||
*/
|
||||
public void revokeAccessToken(String accessToken) {
|
||||
AccessTokenModel at = getAccessToken(accessToken);
|
||||
if(at == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 删 at、索引
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
dao.deleteAccessToken(accessToken);
|
||||
dao.deleteAccessTokenIndex(at.clientId, at.loginId);
|
||||
|
||||
// 删对应的 rt、索引
|
||||
// String rtValue = dao.getRefreshTokenValue(at.clientId, at.loginId);
|
||||
// dao.deleteRefreshToken(rtValue);
|
||||
// dao.deleteRefreshTokenIndex(at.clientId, at.loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 Access-Token,根据索引: clientId、loginId
|
||||
* @param clientId /
|
||||
* @param loginId /
|
||||
*/
|
||||
public void revokeAccessTokenByIndex(String clientId, Object loginId) {
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
|
||||
// 删 at、删索引
|
||||
String accessToken = getAccessTokenValue(clientId, loginId);
|
||||
if(accessToken != null) {
|
||||
dao.deleteAccessToken(accessToken);
|
||||
dao.deleteAccessTokenIndex(clientId, loginId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Refresh-Token 相关 -----------------
|
||||
|
||||
/**
|
||||
* 获取 RefreshTokenModel,无效的 RefreshToken 会返回 null
|
||||
* @param refreshToken /
|
||||
* @return /
|
||||
*/
|
||||
public RefreshTokenModel getRefreshToken(String refreshToken) {
|
||||
return SaOAuth2Manager.getDao().getRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Refresh-Token,成功返回 RefreshTokenModel,失败则抛出异常
|
||||
* @param refreshToken /
|
||||
* @return /
|
||||
*/
|
||||
public RefreshTokenModel checkRefreshToken(String refreshToken) {
|
||||
RefreshTokenModel rt = SaOAuth2Manager.getDao().getRefreshToken(refreshToken);
|
||||
if(rt == null) {
|
||||
throw new SaOAuth2RefreshTokenException("无效 refresh_token: " + refreshToken)
|
||||
.setRefreshToken(refreshToken)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30111);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Refresh-Token,根据索引: clientId、loginId
|
||||
* @param clientId /
|
||||
* @param loginId /
|
||||
* @return /
|
||||
*/
|
||||
public String getRefreshTokenValue(String clientId, Object loginId) {
|
||||
return SaOAuth2Manager.getDao().getRefreshTokenValue(clientId, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 RefreshToken 刷新出一个 AccessToken
|
||||
* @param refreshToken /
|
||||
* @return /
|
||||
*/
|
||||
public AccessTokenModel refreshAccessToken(String refreshToken) {
|
||||
return SaOAuth2Manager.getDataGenerate().refreshAccessToken(refreshToken);
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Client-Token 相关 -----------------
|
||||
|
||||
/**
|
||||
* 获取 ClientTokenModel,无效的 ClientToken 会返回 null
|
||||
* @param clientToken /
|
||||
* @return /
|
||||
*/
|
||||
public ClientTokenModel getClientToken(String clientToken) {
|
||||
return SaOAuth2Manager.getDao().getClientToken(clientToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Client-Token,成功返回 ClientTokenModel,失败则抛出异常
|
||||
* @param clientToken /
|
||||
* @return /
|
||||
*/
|
||||
public ClientTokenModel checkClientToken(String clientToken) {
|
||||
ClientTokenModel ct = getClientToken(clientToken);
|
||||
if(ct == null) {
|
||||
throw new SaOAuth2ClientTokenException("无效 client_token: " + clientToken)
|
||||
.setClientToken(clientToken)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30107);
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ClientToken,根据索引: clientId
|
||||
* @param clientId /
|
||||
* @return /
|
||||
*/
|
||||
public String getClientTokenValue(String clientId) {
|
||||
return SaOAuth2Manager.getDao().getClientTokenValue(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:指定 Client-Token 是否具有指定 Scope 列表,返回 true 或 false
|
||||
* @param clientToken Client-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public boolean hasClientTokenScope(String clientToken, String... scopes) {
|
||||
try {
|
||||
checkClientTokenScope(clientToken, scopes);
|
||||
return true;
|
||||
} catch (SaOAuth2ClientTokenException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定 Client-Token 是否具有指定 Scope 列表,如果不具备则抛出异常
|
||||
* @param clientToken Client-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public void checkClientTokenScope(String clientToken, String... scopes) {
|
||||
if(SaFoxUtil.isEmptyArray(scopes)) {
|
||||
return;
|
||||
}
|
||||
ClientTokenModel ct = checkClientToken(clientToken);
|
||||
for (String scope : scopes) {
|
||||
if(! ct.scopes.contains(scope)) {
|
||||
throw new SaOAuth2ClientTokenScopeException("该 client_token 不具备 scope:" + scope)
|
||||
.setClientToken(clientToken)
|
||||
.setScope(scope)
|
||||
.setCode(SaOAuth2ErrorCode.CODE_30109);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 ClientToken
|
||||
*
|
||||
* @param clientToken /
|
||||
*/
|
||||
public void revokeClientToken(String clientToken) {
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
ClientTokenModel ctModel = dao.getClientToken(clientToken);
|
||||
if(ctModel == null) {
|
||||
ClientTokenModel ct = getClientToken(clientToken);
|
||||
if(ct == null) {
|
||||
return;
|
||||
}
|
||||
// 删 ct、索引
|
||||
// 删 ct、删索引
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
dao.deleteClientToken(clientToken);
|
||||
dao.deleteClientTokenIndex(ctModel.clientId);
|
||||
dao.deleteClientTokenIndex(ct.clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收指定的 ClientToken,根据索引: clientId
|
||||
* 回收 ClientToken,根据索引: clientId
|
||||
*
|
||||
* @param clientId /
|
||||
*/
|
||||
@@ -399,33 +625,30 @@ public class SaOAuth2Template {
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
|
||||
// 删 clientToken
|
||||
String clientToken = dao.getClientTokenValue(clientId);
|
||||
String clientToken = getClientTokenValue(clientId);
|
||||
if(clientToken != null) {
|
||||
dao.deleteClientToken(clientToken);
|
||||
dao.deleteClientTokenIndex(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 PastToken,根据索引: clientId
|
||||
*
|
||||
* @param clientId /
|
||||
*/
|
||||
public void revokePastTokenByIndex(String clientId) {
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
// 删 pastToken
|
||||
String pastToken = dao.getPastTokenValue(clientId);
|
||||
if(pastToken != null) {
|
||||
dao.deletePastToken(pastToken);
|
||||
dao.deletePastTokenIndex(clientId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------- 包装其它 bean 的方法
|
||||
|
||||
/**
|
||||
* 获取:Access-Token Model
|
||||
* @param accessToken /
|
||||
* @return /
|
||||
*/
|
||||
public AccessTokenModel getAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getDao().getAccessToken(accessToken);
|
||||
}
|
||||
// ----------------- 包装其它 bean 的方法 -----------------
|
||||
|
||||
/**
|
||||
* 持久化:用户授权记录
|
||||
@@ -455,8 +678,4 @@ public class SaOAuth2Template {
|
||||
return SaOAuth2Manager.getDataConverter().convertScopeStringToList(lowerScope);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@@ -18,120 +18,52 @@ package cn.dev33.satoken.oauth2.template;
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.CodeModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.RefreshTokenModel;
|
||||
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sa-Token-OAuth2 模块 工具类
|
||||
* Sa-Token OAuth2 模块 工具类
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.23.0
|
||||
*/
|
||||
public class SaOAuth2Util {
|
||||
|
||||
// ------------------- 资源校验API
|
||||
|
||||
|
||||
// ----------------- ClientModel 相关 -----------------
|
||||
|
||||
/**
|
||||
* 根据id获取Client信息, 如果Client为空,则抛出异常
|
||||
* @param clientId 应用id
|
||||
* @return ClientModel
|
||||
* 获取 ClientModel,根据 clientId
|
||||
*
|
||||
* @param clientId /
|
||||
* @return /
|
||||
*/
|
||||
public static SaClientModel getClientModel(String clientId) {
|
||||
return SaOAuth2Manager.getTemplate().getClientModel(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 clientId 信息并返回 ClientModel,如果找不到对应 Client 信息则抛出异常
|
||||
* @param clientId /
|
||||
* @return /
|
||||
*/
|
||||
public static SaClientModel checkClientModel(String clientId) {
|
||||
return SaOAuth2Manager.getTemplate().checkClientModel(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token,如果AccessToken为空则抛出异常
|
||||
* @param accessToken .
|
||||
* @return .
|
||||
*/
|
||||
public static AccessTokenModel checkAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Client-Token,如果ClientToken为空则抛出异常
|
||||
* @param clientToken .
|
||||
* @return .
|
||||
*/
|
||||
public static ClientTokenModel checkClientToken(String clientToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkClientToken(clientToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token 所代表的LoginId
|
||||
* @param accessToken Access-Token
|
||||
* @return LoginId
|
||||
*/
|
||||
public static Object getLoginIdByAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().getLoginIdByAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定 Access-Token 是否具有指定 Scope
|
||||
* @param accessToken Access-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public static void checkScope(String accessToken, String... scopes) {
|
||||
SaOAuth2Manager.getTemplate().checkScope(accessToken, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定 Client-Token 是否具有指定 Scope
|
||||
* @param clientToken Client-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public static void checkClientTokenScope(String clientToken, String... scopes) {
|
||||
SaOAuth2Manager.getTemplate().checkClientTokenScope(clientToken, scopes);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 数据校验
|
||||
|
||||
/**
|
||||
* 判断:指定 loginId 是否对一个 Client 授权给了指定 Scope
|
||||
* @param loginId 账号id
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限
|
||||
* @return 是否已经授权
|
||||
*/
|
||||
public static boolean isGrant(Object loginId, String clientId, List<String> scopes) {
|
||||
return SaOAuth2Manager.getTemplate().isGrant(loginId, clientId, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:该Client是否签约了指定的Scope
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限(多个用逗号隔开)
|
||||
*/
|
||||
public static void checkContract(String clientId, List<String> scopes) {
|
||||
SaOAuth2Manager.getTemplate().checkContract(clientId, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:该Client使用指定url作为回调地址,是否合法
|
||||
* @param clientId 应用id
|
||||
* @param url 指定url
|
||||
*/
|
||||
public static void checkRightUrl(String clientId, String url) {
|
||||
SaOAuth2Manager.getTemplate().checkRightUrl(clientId, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:clientId 与 clientSecret 是否正确
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @return SaClientModel对象
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @return SaClientModel对象
|
||||
*/
|
||||
public static SaClientModel checkClientSecret(String clientId, String clientSecret) {
|
||||
return SaOAuth2Manager.getTemplate().checkClientSecret(clientId, clientSecret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验:clientId 与 clientSecret 是否正确,并且是否签约了指定 scopes
|
||||
* 校验:clientId 与 clientSecret 是否正确,并且是否签约了指定 scopes
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @param scopes 权限
|
||||
@@ -140,43 +72,235 @@ public class SaOAuth2Util {
|
||||
public static SaClientModel checkClientSecretAndScope(String clientId, String clientSecret, List<String> scopes) {
|
||||
return SaOAuth2Manager.getTemplate().checkClientSecretAndScope(clientId, clientSecret, scopes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验:使用 code 获取 token 时提供的参数校验
|
||||
* @param code 授权码
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @param redirectUri 重定向地址
|
||||
* @return CodeModel对象
|
||||
* 判断:该 Client 是否签约了指定的 Scope,返回 true 或 false
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限
|
||||
* @return /
|
||||
*/
|
||||
public static CodeModel checkGainTokenParam(String code, String clientId, String clientSecret, String redirectUri) {
|
||||
return SaOAuth2Manager.getTemplate().checkGainTokenParam(code, clientId, clientSecret, redirectUri);
|
||||
public static boolean isContractScope(String clientId, List<String> scopes) {
|
||||
return SaOAuth2Manager.getTemplate().isContractScope(clientId, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:使用 Refresh-Token 刷新 Access-Token 时提供的参数校验
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @param refreshToken Refresh-Token
|
||||
* @return CodeModel对象
|
||||
* 校验:该 Client 是否签约了指定的 Scope,如果没有则抛出异常
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限列表
|
||||
* @return /
|
||||
*/
|
||||
public static RefreshTokenModel checkRefreshTokenParam(String clientId, String clientSecret, String refreshToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkRefreshTokenParam(clientId, clientSecret, refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:Access-Token、clientId、clientSecret 三者是否匹配成功
|
||||
* @param clientId 应用id
|
||||
* @param clientSecret 秘钥
|
||||
* @param accessToken Access-Token
|
||||
* @return SaClientModel对象
|
||||
*/
|
||||
public static AccessTokenModel checkAccessTokenParam(String clientId, String clientSecret, String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkAccessTokenParam(clientId, clientSecret, accessToken);
|
||||
public static SaClientModel checkContractScope(String clientId, List<String> scopes) {
|
||||
return SaOAuth2Manager.getTemplate().checkContractScope(clientId, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收指定的 ClientToken
|
||||
* 校验:该 Client 是否签约了指定的 Scope,如果没有则抛出异常
|
||||
* @param cm 应用
|
||||
* @param scopes 权限列表
|
||||
* @return /
|
||||
*/
|
||||
public static SaClientModel checkContractScope(SaClientModel cm, List<String> scopes) {
|
||||
return SaOAuth2Manager.getTemplate().checkContractScope(cm, scopes);
|
||||
}
|
||||
|
||||
// --------- redirect_uri 相关
|
||||
|
||||
/**
|
||||
* 校验:该 Client 使用指定 url 作为回调地址,是否合法
|
||||
* @param clientId 应用id
|
||||
* @param url 指定url
|
||||
*/
|
||||
public static void checkRedirectUri(String clientId, String url) {
|
||||
SaOAuth2Manager.getTemplate().checkRedirectUri(clientId, url);
|
||||
}
|
||||
|
||||
// --------- 授权相关
|
||||
|
||||
/**
|
||||
* 判断:指定 loginId 是否对一个 Client 授权给了指定 Scope
|
||||
* @param loginId 账号id
|
||||
* @param clientId 应用id
|
||||
* @param scopes 权限
|
||||
* @return 是否已经授权
|
||||
*/
|
||||
public static boolean isGrantScope(Object loginId, String clientId, List<String> scopes) {
|
||||
return SaOAuth2Manager.getTemplate().isGrantScope(loginId, clientId, scopes);
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Access-Token 相关 -----------------
|
||||
|
||||
/**
|
||||
* 获取 AccessTokenModel,无效的 AccessToken 会返回 null
|
||||
* @param accessToken /
|
||||
* @return /
|
||||
*/
|
||||
public static AccessTokenModel getAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().getAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Access-Token,成功返回 AccessTokenModel,失败则抛出异常
|
||||
* @param accessToken /
|
||||
* @return /
|
||||
*/
|
||||
public static AccessTokenModel checkAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token,根据索引: clientId、loginId
|
||||
* @param clientId /
|
||||
* @param loginId /
|
||||
* @return /
|
||||
*/
|
||||
public static String getAccessTokenValue(String clientId, Object loginId) {
|
||||
return SaOAuth2Manager.getTemplate().getAccessTokenValue(clientId, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:指定 Access-Token 是否具有指定 Scope 列表,返回 true 或 false
|
||||
* @param accessToken Access-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public static boolean hasAccessTokenScope(String accessToken, String... scopes) {
|
||||
return SaOAuth2Manager.getTemplate().hasAccessTokenScope(accessToken, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定 Access-Token 是否具有指定 Scope 列表,如果不具备则抛出异常
|
||||
* @param accessToken Access-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public static void checkAccessTokenScope(String accessToken, String... scopes) {
|
||||
SaOAuth2Manager.getTemplate().checkAccessTokenScope(accessToken, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token 所代表的LoginId
|
||||
* @param accessToken Access-Token
|
||||
* @return LoginId
|
||||
*/
|
||||
public static Object getLoginIdByAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().getLoginIdByAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Access-Token 所代表的 clientId
|
||||
* @param accessToken Access-Token
|
||||
* @return LoginId
|
||||
*/
|
||||
public static Object getClientIdByAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getTemplate().getClientIdByAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 Access-Token
|
||||
* @param accessToken Access-Token值
|
||||
*/
|
||||
public static void revokeAccessToken(String accessToken) {
|
||||
SaOAuth2Manager.getTemplate().revokeAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 Access-Token,根据索引: clientId、loginId
|
||||
* @param clientId /
|
||||
* @param loginId /
|
||||
*/
|
||||
public static void revokeAccessTokenByIndex(String clientId, Object loginId) {
|
||||
SaOAuth2Manager.getTemplate().revokeAccessTokenByIndex(clientId, loginId);
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Refresh-Token 相关 -----------------
|
||||
|
||||
/**
|
||||
* 获取 RefreshTokenModel,无效的 RefreshToken 会返回 null
|
||||
* @param refreshToken /
|
||||
* @return /
|
||||
*/
|
||||
public static RefreshTokenModel getRefreshToken(String refreshToken) {
|
||||
return SaOAuth2Manager.getTemplate().getRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Refresh-Token,成功返回 RefreshTokenModel,失败则抛出异常
|
||||
* @param refreshToken /
|
||||
* @return /
|
||||
*/
|
||||
public static RefreshTokenModel checkRefreshToken(String refreshToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Refresh-Token,根据索引: clientId、loginId
|
||||
* @param clientId /
|
||||
* @param loginId /
|
||||
* @return /
|
||||
*/
|
||||
public static String getRefreshTokenValue(String clientId, Object loginId) {
|
||||
return SaOAuth2Manager.getTemplate().getRefreshTokenValue(clientId, loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 RefreshToken 刷新出一个 AccessToken
|
||||
* @param refreshToken /
|
||||
* @return /
|
||||
*/
|
||||
public static AccessTokenModel refreshAccessToken(String refreshToken) {
|
||||
return SaOAuth2Manager.getTemplate().refreshAccessToken(refreshToken);
|
||||
}
|
||||
|
||||
|
||||
// ----------------- Client-Token 相关 -----------------
|
||||
|
||||
/**
|
||||
* 获取 ClientTokenModel,无效的 ClientToken 会返回 null
|
||||
* @param clientToken /
|
||||
* @return /
|
||||
*/
|
||||
public static ClientTokenModel getClientToken(String clientToken) {
|
||||
return SaOAuth2Manager.getTemplate().getClientToken(clientToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 Client-Token,成功返回 ClientTokenModel,失败则抛出异常
|
||||
* @param clientToken /
|
||||
* @return /
|
||||
*/
|
||||
public static ClientTokenModel checkClientToken(String clientToken) {
|
||||
return SaOAuth2Manager.getTemplate().checkClientToken(clientToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ClientToken,根据索引: clientId
|
||||
* @param clientId /
|
||||
* @return /
|
||||
*/
|
||||
public static String getClientTokenValue(String clientId) {
|
||||
return SaOAuth2Manager.getTemplate().getClientTokenValue(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断:指定 Client-Token 是否具有指定 Scope 列表,返回 true 或 false
|
||||
* @param clientToken Client-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public static boolean hasClientTokenScope(String clientToken, String... scopes) {
|
||||
return SaOAuth2Manager.getTemplate().hasClientTokenScope(clientToken, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验:指定 Client-Token 是否具有指定 Scope 列表,如果不具备则抛出异常
|
||||
* @param clientToken Client-Token
|
||||
* @param scopes 需要校验的权限列表
|
||||
*/
|
||||
public static void checkClientTokenScope(String clientToken, String... scopes) {
|
||||
SaOAuth2Manager.getTemplate().checkClientTokenScope(clientToken, scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收 ClientToken
|
||||
*
|
||||
* @param clientToken /
|
||||
*/
|
||||
@@ -185,7 +309,7 @@ public class SaOAuth2Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* 回收指定的 ClientToken,根据索引:clientId
|
||||
* 回收 ClientToken,根据索引: clientId
|
||||
*
|
||||
* @param clientId /
|
||||
*/
|
||||
@@ -193,65 +317,13 @@ public class SaOAuth2Util {
|
||||
SaOAuth2Manager.getTemplate().revokeClientTokenByIndex(clientId);
|
||||
}
|
||||
|
||||
// ------------------- save 数据
|
||||
|
||||
/**
|
||||
* 持久化:用户授权记录
|
||||
* @param clientId 应用id
|
||||
* @param loginId 账号id
|
||||
* @param scopes 权限列表
|
||||
* 回收 PastToken,根据索引: clientId
|
||||
*
|
||||
* @param clientId /
|
||||
*/
|
||||
public static void saveGrantScope(String clientId, Object loginId, List<String> scopes) {
|
||||
SaOAuth2Manager.getTemplate().saveGrantScope(clientId, loginId, scopes);
|
||||
}
|
||||
|
||||
|
||||
// ------------------- get 数据
|
||||
|
||||
/**
|
||||
* 获取:Code Model
|
||||
* @param code .
|
||||
* @return .
|
||||
*/
|
||||
public static CodeModel getCode(String code) {
|
||||
return SaOAuth2Manager.getDao().getCode(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:Access-Token Model
|
||||
* @param accessToken .
|
||||
* @return .
|
||||
*/
|
||||
public static AccessTokenModel getAccessToken(String accessToken) {
|
||||
return SaOAuth2Manager.getDao().getAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:Refresh-Token Model
|
||||
* @param refreshToken .
|
||||
* @return .
|
||||
*/
|
||||
public static RefreshTokenModel getRefreshToken(String refreshToken) {
|
||||
return SaOAuth2Manager.getDao().getRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:Client-Token Model
|
||||
* @param clientToken .
|
||||
* @return .
|
||||
*/
|
||||
public static ClientTokenModel getClientToken(String clientToken) {
|
||||
return SaOAuth2Manager.getDao().getClientToken(clientToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:用户授权记录
|
||||
* @param clientId 应用id
|
||||
* @param loginId 账号id
|
||||
* @return 权限
|
||||
*/
|
||||
public static List<String> getGrantScope(String clientId, Object loginId) {
|
||||
return SaOAuth2Manager.getDao().getGrantScope(clientId, loginId);
|
||||
public static void revokePastTokenByIndex(String clientId) {
|
||||
SaOAuth2Manager.getTemplate().revokePastTokenByIndex(clientId);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user