目录结构重构完成

This commit is contained in:
shengzhang
2021-05-05 01:02:20 +08:00
parent 5cde169e7f
commit 9965821b51
115 changed files with 185 additions and 33 deletions

View File

@@ -0,0 +1,13 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.factorypath
.idea/
.iml

View File

@@ -0,0 +1,12 @@
# sa-token-oauth2 内测版
sa-token-oauth2 模块是 sa-token 实现 oauth2.0 的部分,目前该模块功能完成度较低,为避免不可预知的风险,建议仅做学习测试使用
## 启动步骤
1. 启动项目 `sa-token-demo-oauth2-server`, 此为OAuth2.0的服务提供方
2. 启动项目 `sa-token-demo-oauth2-client`, 此为OAuth2.0的客户端
3. 根据控制台打印,访问测试地址即可:[http://localhost:8002/login.html](http://localhost:8002/login.html)
可结合代码注释学习查看

View File

@@ -0,0 +1,30 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-plugin</artifactId>
<version>1.18.0</version>
</parent>
<packaging>jar</packaging>
<name>sa-token-dao-redis</name>
<artifactId>sa-token-oauth2</artifactId>
<version>1.15.0-alpha</version>
<description>sa-token realization oauth2.0</description>
<dependencies>
<!-- sa-token-core -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${sa-token-version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,54 @@
package cn.dev33.satoken.oauth2;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Interface;
import cn.dev33.satoken.oauth2.logic.SaOAuth2InterfaceDefaultImpl;
/**
* sa-token oauth2 模块 总控类
*
* @author kong
*
*/
public class SaOAuth2Manager {
/**
* OAuth2 配置 Bean
*/
private static SaOAuth2Config config;
public static SaOAuth2Config getConfig() {
if (config == null) {
// 初始化默认值
synchronized (SaOAuth2Manager.class) {
if (config == null) {
setConfig(new SaOAuth2Config());
}
}
}
return config;
}
public static void setConfig(SaOAuth2Config config) {
SaOAuth2Manager.config = config;
}
/**
* sa-token-oauth2 逻辑 Bean
*/
private static SaOAuth2Interface saOAuth2Interface;
public static SaOAuth2Interface getInterface() {
if (saOAuth2Interface == null) {
// 初始化默认值
synchronized (SaOAuth2Manager.class) {
if (saOAuth2Interface == null) {
setInterface(new SaOAuth2InterfaceDefaultImpl());
}
}
}
return saOAuth2Interface;
}
public static void setInterface(SaOAuth2Interface interfaceObj) {
SaOAuth2Manager.saOAuth2Interface = interfaceObj;
}
}

View File

@@ -0,0 +1,79 @@
package cn.dev33.satoken.oauth2.config;
/**
* sa-token oauth2 配置类 Model
* @author kong
*
*/
public class SaOAuth2Config {
/**
* 授权码默认保存的时间(单位秒) 默认五分钟
*/
private long codeTimeout = 60 * 5;
/**
* access_token默认保存的时间(单位秒) 默认两个小时
*/
private long accessTokenTimeout = 60 * 60 * 2;
/**
* refresh_token默认保存的时间(单位秒) 默认30 天
*/
private long refreshTokenTimeout = 60 * 60 * 24 * 30;
/**
* @return codeTimeout
*/
public long getCodeTimeout() {
return codeTimeout;
}
/**
* @param codeTimeout 要设置的 codeTimeout
* @return 对象自身
*/
public SaOAuth2Config setCodeTimeout(long codeTimeout) {
this.codeTimeout = codeTimeout;
return this;
}
/**
* @return accessTokenTimeout
*/
public long getAccessTokenTimeout() {
return accessTokenTimeout;
}
/**
* @param accessTokenTimeout 要设置的 accessTokenTimeout
* @return 对象自身
*/
public SaOAuth2Config setAccessTokenTimeout(long accessTokenTimeout) {
this.accessTokenTimeout = accessTokenTimeout;
return this;
}
/**
* @return refreshTokenTimeout
*/
public long getRefreshTokenTimeout() {
return refreshTokenTimeout;
}
/**
* @param refreshTokenTimeout 要设置的 refreshTokenTimeout
* @return 对象自身
*/
public SaOAuth2Config setRefreshTokenTimeout(long refreshTokenTimeout) {
this.refreshTokenTimeout = refreshTokenTimeout;
return this;
}
}

View File

@@ -0,0 +1,554 @@
package cn.dev33.satoken.oauth2.logic;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
import cn.dev33.satoken.oauth2.util.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.util.SaOAuth2InsideUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* sa-token-oauth2 模块 逻辑接口
* @author kong
*
*/
public interface SaOAuth2Interface {
// ------------------- 获取数据
/**
* [default] 返回此平台所有权限集合
* @return 此平台所有权限名称集合
*/
public default List<String> getAppScopeList() {
return Arrays.asList("userinfo");
}
/**
* [default] 返回指定Client签约的所有Scope名称集合
* @param clientId 应用id
* @return Scope集合
*/
public default List<String> getClientScopeList(String clientId) {
// 默认返回此APP的所有权限
return getAppScopeList();
}
/**
* [default] 获取指定 LoginId 对指定 Client 已经授权过的所有 Scope
* @param clientId 应用id
* @param loginId 账号id
* @return Scope集合
*/
public default List<String> getGrantScopeList(Object loginId, String clientId) {
// 默认返回空集合
return Arrays.asList();
}
/**
* [default] 返回指定Client允许的回调域名, 多个用逗号隔开, *代表不限制
* @param clientId 应用id
* @return domain集合
*/
public default String getClientDomain(String clientId) {
return "*";
}
/**
* [default] 返回指定ClientId的ClientSecret
* @param clientId 应用id
* @return 此应用的秘钥
*/
public default String getClientSecret(String clientId) {
return null;
}
/**
* [default] 根据ClientId和LoginId返回openid
* @param clientId 应用id
* @param loginId 账号id
* @return 此账号在此Client下的openid
*/
public default String getOpenid(String clientId, Object loginId) {
return null;
}
/**
* [default] 根据ClientId和openid返回LoginId
* @param clientId 应用id
* @param openid openid
* @return LoginId
*/
public default Object getLoginId(String clientId, String openid) {
return null;
}
// ------------------- 数据校验
/**
* [default] 检查一个 Client 是否签约了指定的Scope
* @param clientId 应用id
* @param scope 权限
*/
public default void checkContract(String clientId, String scope) {
List<String> clientScopeList = getClientScopeList(clientId);
List<String> scopelist = Arrays.asList(scope.split(","));
if(clientScopeList.containsAll(scopelist) == false) {
throw new SaTokenException("请求授权范围超出或无效");
}
}
/**
* [default] 指定 loginId 是否对一个 Client 授权给了指定 Scope
* @param loginId 账号id
* @param clientId 应用id
* @param scope 权限
* @return 是否已经授权
*/
public default boolean isGrant(Object loginId, String clientId, String scope) {
List<String> grantScopeList = getGrantScopeList(loginId, clientId);
List<String> scopeList = convertStringToList(scope);
return grantScopeList.containsAll(scopeList);
}
/**
* [default] 指定Client使用指定url作为回调地址是否合法
* @param clientId 应用id
* @param url 指定url
*/
public default void checkRightUrl(String clientId, String url) {
// 首先检测url格式
if(SaOAuth2InsideUtil.isUrl(url) == false) {
throw new SaTokenException("url格式错误");
}
// ---- 检测
// 获取此应用允许的域名列表
String domain = getClientDomain(clientId);
// 如果是null或者空字符串, 则代表任何域名都无法通过检查
if(domain == null || "".equals(domain)) {
throw new SaTokenException("重定向地址无效");
}
// 如果是*符号,代表允许任何域名
if(SaOAuth2Consts.UNLIMITED_DOMAIN.equals(domain)) {
return;
}
// 获取域名进行比对
try {
String host = new URL(url).getHost();
List<String> domainList = convertStringToList(domain);
if(domainList.contains(host) == false) {
throw new SaTokenException("重定向地址不在列表中");
}
} catch (MalformedURLException e) {
throw new SaTokenException("url格式错误", e);
}
}
/**
* [default] 校验code、clientId、clientSecret 三者是否正确
* @param code 授权码
* @param clientId 应用id
* @param clientSecret 秘钥
* @return CodeModel对象
*/
public default CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret) {
// 获取授权码信息
CodeModel codeModel = getCode(code);
// 验证code、client_id、client_secret
if(codeModel == null) {
throw new SaTokenException("无效code");
}
if(codeModel.getClientId().equals(clientId) == false){
throw new SaTokenException("无效client_id");
}
String dbClientSecret = getClientSecret(clientId);
System.out.println(dbClientSecret);
System.out.println(clientSecret);
if(dbClientSecret == null || dbClientSecret.equals(clientSecret) == false){
throw new SaTokenException("无效client_secret");
}
// 返回CodeMdoel
return codeModel;
}
/**
* [default] 校验access_token、clientId、clientSecret 三者是否正确
* @param accessToken access_token
* @param clientId 应用id
* @param clientSecret 秘钥
* @return AccessTokenModel对象
*/
public default AccessTokenModel checkTokenIdSecret(String accessToken, String clientId, String clientSecret) {
// 获取授权码信息
AccessTokenModel tokenModel = getAccessToken(accessToken);
// 验证code、client_id、client_secret
if(tokenModel == null) {
throw new SaTokenException("无效access_token");
}
if(tokenModel.getClientId().equals(clientId) == false){
throw new SaTokenException("无效client_id");
}
String dbClientSecret = getClientSecret(clientId);
if(dbClientSecret == null || dbClientSecret.equals(clientSecret)){
throw new SaTokenException("无效client_secret");
}
// 返回AccessTokenModel
return tokenModel;
}
// ------------------- 逻辑相关
// ---- 授权码
/**
* [default] 根据参数生成一个授权码并返回
* @param authModel 请求授权参数Model
* @return 授权码Model
*/
public default CodeModel generateCode(RequestAuthModel authModel) {
// 获取参数
String clientId = authModel.getClientId();
String scope = authModel.getScope();
Object loginId = authModel.getLoginId();
String redirectUri = authModel.getRedirectUri();
String state = authModel.getState();
// ------ 参数校验
// 此Client是否签约了此Scope
checkContract(clientId, scope);
// 校验重定向域名的格式是否合法
checkRightUrl(clientId, redirectUri);
// ------ 开始生成code码
String code = createCode(clientId, scope, loginId);
CodeModel codeModel = new CodeModel(code, clientId, scope, loginId);
// 拼接授权后重定向的域名 (拼接code和state参数)
String url = splicingParame(redirectUri, "code=" + code);
if(state != null) {
url = splicingParame(url, "state=" + state);
}
codeModel.setRedirectUri(url);
// 拒绝授权时重定向的地址
codeModel.setRejectUri(splicingParame(redirectUri, "handle=reject"));
// 计算此Scope是否已经授权过了
codeModel.setIsConfirm(isGrant(loginId, clientId, scope));
// ------ 开始保存
// 将此授权码保存到DB
long codeTimeout = SaOAuth2Manager.getConfig().getCodeTimeout();
SaManager.getSaTokenDao().setObject(getKeyCodeModel(code), codeModel, codeTimeout);
// 如果此[Client&账号]已经有code正在存储则先删除它
String key = getKeyClientLoginId(loginId, clientId);
SaManager.getSaTokenDao().delete(key);
// 将此[Client&账号]的最新授权码保存到DB中
// 以便于完成授权码覆盖操作: 保证每次只有最新的授权码有效
SaManager.getSaTokenDao().set(key, code, codeTimeout);
// 返回
return codeModel;
}
/**
* [default] 根据授权码获得授权码Model
* @param code 授权码
* @return 授权码Model
*/
public default CodeModel getCode(String code) {
return (CodeModel)SaManager.getSaTokenDao().getObject(getKeyCodeModel(code));
}
/**
* [default] 手动更改授权码对象信息
* @param code 授权码
* @param codeModel 授权码Model
*/
public default void updateCode(String code, CodeModel codeModel) {
SaManager.getSaTokenDao().updateObject(getKeyCodeModel(code), codeModel);
}
/**
* [default] 确认授权一个code
* @param code 授权码
*/
public default void confirmCode(String code) {
// 获取codeModel
CodeModel codeModel = getCode(code);
// 如果该code码已经确认
if(codeModel.getIsConfirm() == true) {
return;
}
// 进行确认
codeModel.setIsConfirm(true);
updateCode(code, codeModel);
}
/**
* [default] 删除一个授权码
* @param code 授权码
*/
public default void deleteCode(String code) {
SaManager.getSaTokenDao().deleteObject(getKeyCodeModel(code));
}
// ------------------- access_token 和 refresh_token 相关
/**
* [default] 根据授权码Model生成一个access_token
* @param codeModel 授权码Model
* @return AccessTokenModel
*/
public default AccessTokenModel generateAccessToken(CodeModel codeModel) {
// 先校验
if(codeModel == null) {
throw new SaTokenException("无效code");
}
if(codeModel.getIsConfirm() == false) {
throw new SaTokenException("该code尚未授权");
}
// 获取 TokenModel 并保存
AccessTokenModel tokenModel = converCodeToAccessToken(codeModel);
SaManager.getSaTokenDao().setObject(getKeyAccessToken(tokenModel.getAccessToken()), tokenModel, SaOAuth2Manager.getConfig().getAccessTokenTimeout());
// 将此 CodeModel 当做 refresh_token 保存下来
SaManager.getSaTokenDao().setObject(getKeyRefreshToken(tokenModel.getRefreshToken()), codeModel, SaOAuth2Manager.getConfig().getRefreshTokenTimeout());
// 返回
return tokenModel;
}
/**
* [default] 根据 access_token 获得其Model详细信息
* @param accessToken access_token
* @return AccessTokenModel (授权码Model)
*/
public default AccessTokenModel getAccessToken(String accessToken) {
return (AccessTokenModel)SaManager.getSaTokenDao().getObject(getKeyAccessToken(accessToken));
}
/**
* [default] 根据 refresh_token 生成一个新的 access_token
* @param refreshToken refresh_token
* @return 新的 access_token
*/
public default AccessTokenModel refreshAccessToken(String refreshToken) {
// 获取Model信息
CodeModel codeModel = getRefreshToken(refreshToken);
if(codeModel == null) {
throw new SaTokenException("无效refresh_token");
}
// 获取新的 AccessToken 并保存
AccessTokenModel tokenModel = converCodeToAccessToken(codeModel);
tokenModel.setRefreshToken(refreshToken);
SaManager.getSaTokenDao().setObject(getKeyAccessToken(tokenModel.getAccessToken()), tokenModel, SaOAuth2Manager.getConfig().getAccessTokenTimeout());
// 返回
return tokenModel;
}
/**
* [default] 根据 refresh_token 获得其Model详细信息 (授权码Model)
* @param refreshToken refresh_token
* @return RefreshToken (授权码Model)
*/
public default CodeModel getRefreshToken(String refreshToken) {
return (CodeModel)SaManager.getSaTokenDao().getObject(getKeyRefreshToken(refreshToken));
}
/**
* [default] 获取 access_token 的有效期
* @param accessToken access_token
* @return 有效期
*/
public default long getAccessTokenExpiresIn(String accessToken) {
return SaManager.getSaTokenDao().getObjectTimeout(getKeyAccessToken(accessToken));
}
/**
* [default] 获取 refresh_token 的有效期
* @param refreshToken refresh_token
* @return 有效期
*/
public default long getRefreshTokenExpiresIn(String refreshToken) {
return SaManager.getSaTokenDao().getObjectTimeout(getKeyRefreshToken(refreshToken));
}
/**
* [default] 获取 access_token 所代表的LoginId
* @param accessToken access_token
* @return LoginId
*/
public default Object getLoginIdByAccessToken(String accessToken) {
AccessTokenModel tokenModel = SaOAuth2Util.getAccessToken(accessToken);
if(tokenModel == null) {
throw new SaTokenException("无效access_token");
}
return getLoginId(tokenModel.getClientId(), tokenModel.getOpenid());
}
// ------------------- 自定义策略相关
/**
* [default] 将指定字符串按照逗号分隔符转化为字符串集合
* @param str 字符串
* @return 分割后的字符串集合
*/
public default List<String> convertStringToList(String str) {
return Arrays.asList(str.split(","));
}
/**
* [default] 生成授权码
* @param clientId 应用id
* @param scope 权限
* @param loginId 账号id
* @return 授权码
*/
public default String createCode(String clientId, String scope, Object loginId) {
return SaFoxUtil.getRandomString(60).toLowerCase();
}
/**
* [default] 生成AccessToken
* @param codeModel CodeModel对象
* @return AccessToken
*/
public default String createAccessToken(CodeModel codeModel) {
return SaFoxUtil.getRandomString(60).toLowerCase();
}
/**
* [default] 生成RefreshToken
* @param codeModel CodeModel对象
* @return RefreshToken
*/
public default String createRefreshToken(CodeModel codeModel) {
return SaFoxUtil.getRandomString(60).toLowerCase();
}
/**
* [default] 在url上拼接上kv参数并返回
* @param url url
* @param parameStr 参数, 例如 id=1001
* @return 拼接后的url字符串
*/
public default String splicingParame(String url, String parameStr) {
// 如果参数为空, 直接返回
if(parameStr == null || parameStr.length() == 0) {
return url;
}
int index = url.indexOf('?');
// ? 不存在
if(index == -1) {
return url + '?' + parameStr;
}
// ? 是最后一位
if(index == url.length() - 1) {
return url + parameStr;
}
// ? 是其中一位
if(index > -1 && index < url.length() - 1) {
String separatorChar = "&";
// 如果最后一位是 不是&, 且 arg_str 第一位不是 &, 就增送一个 &
if(url.lastIndexOf(separatorChar) != url.length() - 1 && parameStr.indexOf(separatorChar) != 0) {
return url + separatorChar + parameStr;
} else {
return url + parameStr;
}
}
// 正常情况下, 代码不可能执行到此
return url;
}
/**
* [default] 将 CodeModel 转换为 AccessTokenModel
* @param codeModel CodeModel对象
* @return AccessToken对象
*/
public default AccessTokenModel converCodeToAccessToken(CodeModel codeModel) {
if(codeModel == null) {
throw new SaTokenException("无效code");
}
AccessTokenModel tokenModel = new AccessTokenModel();
tokenModel.setAccessToken(createAccessToken(codeModel));
tokenModel.setRefreshToken(createRefreshToken(codeModel));
tokenModel.setCode(codeModel.getCode());
tokenModel.setClientId(codeModel.getClientId());
tokenModel.setScope(codeModel.getScope());
tokenModel.setOpenid(getOpenid(codeModel.getClientId(), codeModel.getLoginId()));
tokenModel.setTag(codeModel.getTag());
return tokenModel;
}
// ------------------- 返回相应key
/**
* 获取key授权码持久化使用的key
* @param code 授权码
* @return key
*/
public default String getKeyCodeModel(String code) {
return SaManager.getConfig().getTokenName() + ":oauth2:code:" + code;
}
/**
* 获取key[Client and 账号]最新授权码记录, 持久化使用的key
* @param loginId 账号id
* @param clientId 应用id
* @return key
*/
public default String getKeyClientLoginId(Object loginId, String clientId) {
return SaManager.getConfig().getTokenName() + ":oauth2:newest-code:" + clientId + ":" + loginId;
}
/**
* 获取keyrefreshToken持久化使用的key
* @param refreshToken refreshToken
* @return key
*/
public default String getKeyRefreshToken(String refreshToken) {
return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken;
}
/**
* 获取keyaccessToken持久化使用的key
* @param accessToken accessToken
* @return key
*/
public default String getKeyAccessToken(String accessToken) {
return SaManager.getConfig().getTokenName() + ":oauth2:access-token:" + accessToken;
}
}

View File

@@ -0,0 +1,12 @@
package cn.dev33.satoken.oauth2.logic;
/**
* SaOAuth2Interface 默认实现类 (只构建userinfo单个权限)
* @author kong
*
*/
public class SaOAuth2InterfaceDefaultImpl implements SaOAuth2Interface {
}

View File

@@ -0,0 +1,198 @@
package cn.dev33.satoken.oauth2.logic;
import java.util.List;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
/**
* sa-token-oauth2 模块 静态类接口转发, 方便调用
* @author kong
*
*/
public class SaOAuth2Util {
// ------------------- 获取数据
/**
* 返回此平台所有权限集合
* @return 此平台所有权限名称集合
*/
public static List<String> getAppScopeList() {
return SaOAuth2Manager.getInterface().getAppScopeList();
}
/**
* 返回指定Client签约的所有Scope名称集合
* @param clientId 应用id
* @return Scope集合
*/
public static List<String> getClientScopeList(String clientId) {
return SaOAuth2Manager.getInterface().getClientScopeList(clientId);
}
/**
* 获取指定 LoginId 对指定 Client 已经授权过的所有 Scope
* @param clientId 应用id
* @param loginId 账号id
* @return Scope集合
*/
public static List<String> getGrantScopeList(Object loginId, String clientId) {
return SaOAuth2Manager.getInterface().getGrantScopeList(loginId, clientId);
}
// ------------------- 数据校验
/**
* 指定 loginId 是否对一个 Client 授权给了指定 Scope
* @param clientId 应用id
* @param scope 权限
* @param loginId 账号id
* @return 是否已经授权
*/
public static boolean isGrant(Object loginId, String clientId, String scope) {
return SaOAuth2Manager.getInterface().isGrant(loginId, clientId, scope);
}
/**
* 校验code、clientId、clientSecret 三者是否正确
* @param code 授权码
* @param clientId 应用id
* @param clientSecret 秘钥
* @return CodeModel对象
*/
public static CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret) {
return SaOAuth2Manager.getInterface().checkCodeIdSecret(code, clientId, clientSecret);
}
/**
* [default] 校验access_token、clientId、clientSecret 三者是否正确
* @param accessToken access_token
* @param clientId 应用id
* @param clientSecret 秘钥
* @return AccessTokenModel对象
*/
public static AccessTokenModel checkTokenIdSecret(String accessToken, String clientId, String clientSecret) {
return SaOAuth2Manager.getInterface().checkTokenIdSecret(accessToken, clientId, clientSecret);
}
// ------------------- 逻辑相关
/**
* 根据参数生成一个授权码并返回
* @param authModel 请求授权参数Model
* @return 授权码Model
*/
public static CodeModel generateCode(RequestAuthModel authModel) {
return SaOAuth2Manager.getInterface().generateCode(authModel);
}
/**
* 根据授权码获得授权码Model
* @param code 授权码
* @return 授权码Model
*/
public static CodeModel getCode(String code) {
return SaOAuth2Manager.getInterface().getCode(code);
}
/**
* 手动更改授权码对象信息
* @param code 授权码
* @param codeModel 授权码Model
*/
public static void updateCode(String code, CodeModel codeModel) {
SaOAuth2Manager.getInterface().updateCode(code, codeModel);
}
/**
* 确认授权一个code
* @param code 授权码
*/
public static void confirmCode(String code) {
SaOAuth2Manager.getInterface().confirmCode(code);
}
/**
* [default] 删除一个授权码
* @param code 授权码
*/
public static void deleteCode(String code) {
SaOAuth2Manager.getInterface().deleteCode(code);
}
/**
* [default] 根据授权码Model生成一个access_token
* @param codeModel 授权码Model
* @return AccessTokenModel
*/
public static AccessTokenModel generateAccessToken(CodeModel codeModel) {
return SaOAuth2Manager.getInterface().generateAccessToken(codeModel);
}
/**
* [default] 根据 access_token 获得其Model详细信息
* @param accessToken access_token
* @return AccessTokenModel (授权码Model)
*/
public static AccessTokenModel getAccessToken(String accessToken) {
return SaOAuth2Manager.getInterface().getAccessToken(accessToken);
}
/**
* 根据 refresh_token 生成一个新的 access_token
* @param refreshToken refresh_token
* @return 新的 access_token
*/
public static AccessTokenModel refreshAccessToken(String refreshToken) {
return SaOAuth2Manager.getInterface().refreshAccessToken(refreshToken);
}
/**
* [default] 根据 refresh_token 获得其Model详细信息 (授权码Model)
* @param refreshToken refresh_token
* @return RefreshToken (授权码Model)
*/
public static CodeModel getRefreshToken(String refreshToken) {
return SaOAuth2Manager.getInterface().getRefreshToken(refreshToken);
}
/**
* [default] 获取 access_token 的有效期
* @param accessToken access_token
* @return 有效期
*/
public static long getAccessTokenExpiresIn(String accessToken) {
return SaOAuth2Manager.getInterface().getAccessTokenExpiresIn(accessToken);
}
/**
* [default] 获取 refresh_token 的有效期
* @param refreshToken refresh_token
* @return 有效期
*/
public static long getRefreshTokenExpiresIn(String refreshToken) {
return SaOAuth2Manager.getInterface().getRefreshTokenExpiresIn(refreshToken);
}
/**
* [default] 获取 access_token 所代表的LoginId
* @param accessToken access_token
* @return LoginId
*/
public static Object getLoginIdByAccessToken(String accessToken) {
return SaOAuth2Manager.getInterface().getLoginIdByAccessToken(accessToken);
}
}

View File

@@ -0,0 +1,186 @@
package cn.dev33.satoken.oauth2.model;
/**
* Model: access_token
* @author kong
*
*/
public class AccessTokenModel {
/**
* access_token 值
*/
private String accessToken;
/**
* refresh_token 值
*/
private String refreshToken;
/**
* access_token 剩余有效时间 (秒)
*/
private long expiresIn;
/**
* refresh_token 剩余有效期 (秒)
*/
private long refreshExpiresIn;
/**
* 此 access_token令牌 是由哪个code码创建
*/
private String code;
/**
* 应用id
*/
private String clientId;
/**
* 授权范围
*/
private String scope;
/**
* 开放账号id
*/
private String openid;
/**
* 其他自定义数据
*/
private Object tag;
/**
* @return accessToken
*/
public String getAccessToken() {
return accessToken;
}
/**
* @param accessToken 要设置的 accessToken
*/
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
/**
* @return refreshToken
*/
public String getRefreshToken() {
return refreshToken;
}
/**
* @param refreshToken 要设置的 refreshToken
*/
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
/**
* @return expiresIn
*/
public long getExpiresIn() {
return expiresIn;
}
/**
* @param expiresIn 要设置的 expiresIn
*/
public void setExpiresIn(long expiresIn) {
this.expiresIn = expiresIn;
}
/**
* @return refreshExpiresIn
*/
public long getRefreshExpiresIn() {
return refreshExpiresIn;
}
/**
* @param refreshExpiresIn 要设置的 refreshExpiresIn
*/
public void setRefreshExpiresIn(long refreshExpiresIn) {
this.refreshExpiresIn = refreshExpiresIn;
}
/**
* @return code
*/
public String getCode() {
return code;
}
/**
* @param code 要设置的 code
*/
public void setCode(String code) {
this.code = code;
}
/**
* @return clientId
*/
public String getClientId() {
return clientId;
}
/**
* @param clientId 要设置的 clientId
*/
public void setClientId(String clientId) {
this.clientId = clientId;
}
/**
* @return scope
*/
public String getScope() {
return scope;
}
/**
* @param scope 要设置的 scope
*/
public void setScope(String scope) {
this.scope = scope;
}
/**
* @return openid
*/
public String getOpenid() {
return openid;
}
/**
* @param openid 要设置的 openid
*/
public void setOpenid(String openid) {
this.openid = openid;
}
/**
* @return tag
*/
public Object getTag() {
return tag;
}
/**
* @param tag 要设置的 tag
*/
public void setTag(Object tag) {
this.tag = tag;
}
}

View File

@@ -0,0 +1,191 @@
package cn.dev33.satoken.oauth2.model;
/**
* Model: [授权码 - 数据 对应关系]
* @author kong
*
*/
public class CodeModel {
/**
* 授权码
*/
private String code;
/**
* 应用id
*/
private String clientId;
/**
* 授权范围
*/
private String scope;
/**
* 对应账号id
*/
private Object loginId;
/**
* 用户是否已经确认了这个授权
*/
private Boolean isConfirm;
/**
* 确认授权后重定向的地址
*/
private String redirectUri;
/**
* 拒绝授权后重定向的地址
*/
private String rejectUri;
/**
* 其他自定义数据
*/
private Object tag;
/**
* 构建一个
*/
public CodeModel() {
}
/**
* 构建一个
* @param code 授权码
* @param clientId 应用id
* @param scope 请求授权范围
* @param loginId 对应的账号id
*/
public CodeModel(String code, String clientId, String scope, Object loginId) {
super();
this.code = code;
this.clientId = clientId;
this.scope = scope;
this.loginId = loginId;
this.isConfirm = false;
}
/**
* @return code
*/
public String getCode() {
return code;
}
/**
* @param code 要设置的 code
*/
public void setCode(String code) {
this.code = code;
}
/**
* @return clientId
*/
public String getClientId() {
return clientId;
}
/**
* @param clientId 要设置的 clientId
*/
public void setClientId(String clientId) {
this.clientId = clientId;
}
/**
* @return scope
*/
public String getScope() {
return scope;
}
/**
* @param scope 要设置的 scope
*/
public void setScope(String scope) {
this.scope = scope;
}
/**
* @return loginId
*/
public Object getLoginId() {
return loginId;
}
/**
* @param loginId 要设置的 loginId
*/
public void setLoginId(Object loginId) {
this.loginId = loginId;
}
/**
* @return isConfirm
*/
public Boolean getIsConfirm() {
return isConfirm;
}
/**
* @param isConfirm 要设置的 isConfirm
*/
public void setIsConfirm(Boolean isConfirm) {
this.isConfirm = isConfirm;
}
/**
* @return redirectUri
*/
public String getRedirectUri() {
return redirectUri;
}
/**
* @param redirectUri 要设置的 redirectUri
*/
public void setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri;
}
/**
* @return rejectUri
*/
public String getRejectUri() {
return rejectUri;
}
/**
* @param rejectUri 要设置的 rejectUri
*/
public void setRejectUri(String rejectUri) {
this.rejectUri = rejectUri;
}
/**
* @return tag
*/
public Object getTag() {
return tag;
}
/**
* @param tag 要设置的 tag
*/
public void setTag(Object tag) {
this.tag = tag;
}
}

View File

@@ -0,0 +1,160 @@
package cn.dev33.satoken.oauth2.model;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* 请求授权参数的Model
* @author kong
*
*/
public class RequestAuthModel {
/**
* 应用id
*/
private String clientId;
/**
* 授权范围
*/
private String scope;
/**
* 对应的账号id
*/
private Object loginId;
/**
* 待重定向URL
*/
private String redirectUri;
/**
* 授权类型, 非必填
*/
private String responseType;
/**
* 状态标识, 可为null
*/
private String state;
/**
* @return clientId
*/
public String getClientId() {
return clientId;
}
/**
* @param clientId 要设置的 clientId
* @return 对象自身
*/
public RequestAuthModel setClientId(String clientId) {
this.clientId = clientId;
return this;
}
/**
* @return scope
*/
public String getScope() {
return scope;
}
/**
* @param scope 要设置的 scope
* @return 对象自身
*/
public RequestAuthModel setScope(String scope) {
this.scope = scope;
return this;
}
/**
* @return loginId
*/
public Object getLoginId() {
return loginId;
}
/**
* @param loginId 要设置的 loginId
* @return 对象自身
*/
public RequestAuthModel setLoginId(Object loginId) {
this.loginId = loginId;
return this;
}
/**
* @return redirectUri
*/
public String getRedirectUri() {
return redirectUri;
}
/**
* @param redirectUri 要设置的 redirectUri
* @return 对象自身
*/
public RequestAuthModel setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri;
return this;
}
/**
* @return responseType
*/
public String getResponseType() {
return responseType;
}
/**
* @param responseType 要设置的 responseType
* @return 对象自身
*/
public RequestAuthModel setResponseType(String responseType) {
this.responseType = responseType;
return this;
}
/**
* @return state
*/
public String getState() {
return state;
}
/**
* @param state 要设置的 state
* @return 对象自身
*/
public RequestAuthModel setState(String state) {
this.state = state;
return this;
}
/**
* 检查此Model参数是否有效
* @return 对象自身
*/
public RequestAuthModel checkModel() {
if(SaFoxUtil.isEmpty(clientId)) {
throw new SaTokenException("无效client_id");
}
if(SaFoxUtil.isEmpty(scope)) {
throw new SaTokenException("无效scope");
}
if(SaFoxUtil.isEmpty(redirectUri)) {
throw new SaTokenException("无效redirect_uri");
}
if(SaFoxUtil.isEmpty(String.valueOf(loginId))) {
throw new SaTokenException("无效LoginId");
}
return this;
}
}

View File

@@ -0,0 +1,73 @@
package cn.dev33.satoken.oauth2.model;
/**
* 权限Model
* @author kong
*
*/
public class ScopeModel {
/**
* 权限名称
*/
private String name;
/**
* 详细介绍
*/
private String introduce;
/**
* 构造一个
*/
public ScopeModel() {
super();
}
/**
* 构造一个
* @param name 权限名称
* @param introduce 权限详细介绍
*/
public ScopeModel(String name, String introduce) {
super();
this.name = name;
this.introduce = introduce;
}
/**
* @return name
*/
public String getName() {
return name;
}
/**
* @param name 要设置的 name
*/
public void setName(String name) {
this.name = name;
}
/**
* @return introduce
*/
public String getIntroduce() {
return introduce;
}
/**
* @param introduce 要设置的 introduce
*/
public void setIntroduce(String introduce) {
this.introduce = introduce;
}
}

View File

@@ -0,0 +1,19 @@
package cn.dev33.satoken.oauth2.util;
/**
* sa-token oauth2 模块 用到的所有常量
* @author kong
*
*/
public class SaOAuth2Consts {
/**
* 在保存授权码时用到的key
*/
public static final String UNLIMITED_DOMAIN = "*";
}

View File

@@ -0,0 +1,28 @@
package cn.dev33.satoken.oauth2.util;
/**
* sa-token-oauth2 模块内部算法util
* @author kong
*
*/
public class SaOAuth2InsideUtil {
/**
* 验证URL的正则表达式
*/
static final String URL_REGEX = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
/**
* 使用正则表达式判断一个字符串是否为URL
* @param str 字符串
* @return 拼接后的url字符串
*/
public static boolean isUrl(String str) {
if(str == null) {
return false;
}
return str.toLowerCase().matches(URL_REGEX);
}
}