diff --git a/src/main/java/me/zhyd/oauth/config/AuthConfig.java b/src/main/java/me/zhyd/oauth/config/AuthConfig.java index 153585eddfbdfe009ed207f4382169ad1c2f798d..c9dffc7258567dd522404b6314a4fd26d2dbcc0b 100644 --- a/src/main/java/me/zhyd/oauth/config/AuthConfig.java +++ b/src/main/java/me/zhyd/oauth/config/AuthConfig.java @@ -2,8 +2,11 @@ package me.zhyd.oauth.config; import com.xkcoding.http.config.HttpConfig; import lombok.*; +import me.zhyd.oauth.enums.scope.AuthScope; import me.zhyd.oauth.model.AuthCallback; +import java.util.List; + /** * JustAuth配置类 * @@ -64,7 +67,7 @@ public class AuthConfig { /** * 使用 Coding 登录时,需要传该值。 - * + *

* 团队域名前缀,比如以“ https://justauth.coding.net/ ”为例,{@code codingGroupName} = justauth * * @since 1.15.5 @@ -84,18 +87,27 @@ public class AuthConfig { /** * 忽略校验 {@code state} 参数,默认不开启。当 {@code ignoreCheckState} 为 {@code true} 时, * {@link me.zhyd.oauth.request.AuthDefaultRequest#login(AuthCallback)} 将不会校验 {@code state} 的合法性。 - * + *

* 使用场景:当且仅当使用自实现 {@code state} 校验逻辑时开启 - * + *

* 以下场景使用方案仅作参考: * 1. 授权、登录为同端,并且全部使用 JustAuth 实现时,该值建议设为 {@code false}; * 2. 授权和登录为不同端实现时,比如前端页面拼装 {@code authorizeUrl},并且前端自行对{@code state}进行校验, * 后端只负责使用{@code code}获取用户信息时,该值建议设为 {@code true}; * * 如非特殊需要,不建议开启这个配置 - * + *

* 该方案主要为了解决以下类似场景的问题: + * * @see https://github.com/justauth/JustAuth/issues/83 + * @since 1.15.6 */ private boolean ignoreCheckState; + + /** + * 支持自定义授权平台的 scope 内容 + * + * @since 1.15.7 + */ + private List scopes; } diff --git a/src/main/java/me/zhyd/oauth/enums/scope/AuthBaiduScope.java b/src/main/java/me/zhyd/oauth/enums/scope/AuthBaiduScope.java new file mode 100644 index 0000000000000000000000000000000000000000..aaec676109542d246508ab47e7c41f52608a151f --- /dev/null +++ b/src/main/java/me/zhyd/oauth/enums/scope/AuthBaiduScope.java @@ -0,0 +1,48 @@ +package me.zhyd.oauth.enums.scope; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 边度平台 OAuth 授权范围 + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.0.0 + */ +@Getter +@AllArgsConstructor +public enum AuthBaiduScope implements AuthScope { + + /** + * {@code scope} 含义,以{@code description} 为准 + */ + BASIC("basic", "用户基本权限,可以获取用户的基本信息 。", true), + SUPER_MSG("super_msg", "往用户的百度首页上发送消息提醒,相关API任何应用都能使用,但要想将消息提醒在百度首页显示,需要第三方在注册应用时额外填写相关信息。", false), + NETDISK("netdisk", "获取用户在个人云存储中存放的数据。", false), + PUBLIC("public", "可以访问公共的开放API。", false), + HAO123("hao123", "可以访问Hao123 提供的开放API接口。该权限需要申请开通,请将具体的理由和用途发邮件给tuangou@baidu.com。", false); + + private String scope; + private String description; + private boolean isDefault; + + public static List getDefaultScopes() { + AuthBaiduScope[] scopes = AuthBaiduScope.values(); + List defaultScopes = new ArrayList<>(); + for (AuthBaiduScope scope : scopes) { + if (scope.isDefault()) { + defaultScopes.add(scope); + } + } + return defaultScopes; + } + + public static List listAll() { + return Arrays.asList(AuthBaiduScope.values()); + } +} diff --git a/src/main/java/me/zhyd/oauth/enums/scope/AuthCodingScope.java b/src/main/java/me/zhyd/oauth/enums/scope/AuthCodingScope.java new file mode 100644 index 0000000000000000000000000000000000000000..cbaa315b6d450d3250477afc95a3cca36a33b545 --- /dev/null +++ b/src/main/java/me/zhyd/oauth/enums/scope/AuthCodingScope.java @@ -0,0 +1,49 @@ +package me.zhyd.oauth.enums.scope; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Coding平台 OAuth 授权范围 + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.0.0 + */ +@Getter +@AllArgsConstructor +public enum AuthCodingScope implements AuthScope { + + /** + * {@code scope} 含义,以{@code description} 为准 + */ + USER("user", "读取用户的基本信息", false), + USER_EMAIL("user:email", "读取用户的邮件", false), + USER_PHONE("user:phone", "读取用户的手机号", false), + PROJECT("project", "授权项目信息、项目列表,仓库信息,公钥列表、成员", false), + PROJECT_DEPOT("project:depot", "完整的仓库控制权限", false), + PROJECT_WIKI("project:wiki", "授权读取与操作 wiki", false), + ; + private String scope; + private String description; + private boolean isDefault; + + public static List getDefaultScopes() { + AuthCodingScope[] scopes = AuthCodingScope.values(); + List defaultScopes = new ArrayList<>(); + for (AuthCodingScope scope : scopes) { + if (scope.isDefault()) { + defaultScopes.add(scope); + } + } + return defaultScopes; + } + + public static List listAll() { + return Arrays.asList(AuthCodingScope.values()); + } +} diff --git a/src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java b/src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java index 4e8f5c83dafb1ffefd0870bb54ce43355f30194c..fec4ae8449ce5f6ece9cd8130cb524640b324e0b 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java @@ -1,17 +1,18 @@ package me.zhyd.oauth.request; import com.alibaba.fastjson.JSONObject; -import me.zhyd.oauth.utils.HttpUtils; import me.zhyd.oauth.cache.AuthStateCache; import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.config.AuthDefaultSource; import me.zhyd.oauth.enums.AuthResponseStatus; import me.zhyd.oauth.enums.AuthUserGender; +import me.zhyd.oauth.enums.scope.AuthBaiduScope; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthToken; import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.utils.HttpUtils; import me.zhyd.oauth.utils.StringUtils; import me.zhyd.oauth.utils.UrlBuilder; @@ -41,6 +42,7 @@ public class AuthBaiduRequest extends AuthDefaultRequest { * https://openapi.baidu.com/rest/2.0/passport/users/getInfo?access_token=121.c86e87cc0828cc1dabb8faee540531d4.YsUIAWvYbgqVni1VhkgKgyLh8nEyELbDOEZs_OA.OgDgmA * https://openapi.baidu.com/rest/2.0/passport/users/getInfo?access_token=121.2907d9facf9fb97adf7287fa75496eda.Y3NSjR3-3HKt1RgT0HEl7GgxRXT5gOOVdngXezY.OcC_7g * 新旧应用返回的用户信息不一致 + * * @param authToken token信息 * @return AuthUser */ @@ -106,6 +108,7 @@ public class AuthBaiduRequest extends AuthDefaultRequest { .queryParam("client_id", config.getClientId()) .queryParam("redirect_uri", config.getRedirectUri()) .queryParam("display", "popup") + .queryParam("scope", this.getScopes(" ", false, AuthBaiduScope.getDefaultScopes())) .queryParam("state", getRealState(state)) .build(); } diff --git a/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java b/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java index 8acf798299dcd229a7188b7c743eedbb865441de..65c734bf7e2814aff9df7758b117697842c8e556 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java @@ -5,6 +5,7 @@ import me.zhyd.oauth.cache.AuthStateCache; import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.config.AuthDefaultSource; import me.zhyd.oauth.enums.AuthUserGender; +import me.zhyd.oauth.enums.scope.AuthCodingScope; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthToken; @@ -87,10 +88,11 @@ public class AuthCodingRequest extends AuthDefaultRequest { .queryParam("response_type", "code") .queryParam("client_id", config.getClientId()) .queryParam("redirect_uri", config.getRedirectUri()) - .queryParam("scope", "user") + .queryParam("scope", this.getScopes(" ", true, AuthCodingScope.getDefaultScopes())) .queryParam("state", getRealState(state)) .build(); } + /** * 返回获取accessToken的url * @@ -98,7 +100,7 @@ public class AuthCodingRequest extends AuthDefaultRequest { * @return 返回获取accessToken的url */ @Override - public String accessTokenUrl(String code) { + public String accessTokenUrl(String code) { return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getCodingGroupName())) .queryParam("code", code) .queryParam("client_id", config.getClientId()) @@ -115,7 +117,7 @@ public class AuthCodingRequest extends AuthDefaultRequest { * @return 返回获取userInfo的url */ @Override - public String userInfoUrl(AuthToken authToken) { + public String userInfoUrl(AuthToken authToken) { return UrlBuilder.fromBaseUrl(String.format(source.userInfo(), config.getCodingGroupName())) .queryParam("access_token", authToken.getAccessToken()) .build(); diff --git a/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java b/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java index 241840008717da963680ebff7f7dd472081abf21..86707fde3720f8c8233b11441e1e99eead9ecfb3 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java @@ -1,21 +1,21 @@ package me.zhyd.oauth.request; -import me.zhyd.oauth.utils.HttpUtils; +import com.xkcoding.http.util.UrlUtil; import me.zhyd.oauth.cache.AuthDefaultStateCache; import me.zhyd.oauth.cache.AuthStateCache; import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.config.AuthSource; import me.zhyd.oauth.enums.AuthResponseStatus; +import me.zhyd.oauth.enums.scope.AuthScope; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.log.Log; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthToken; import me.zhyd.oauth.model.AuthUser; -import me.zhyd.oauth.utils.AuthChecker; -import me.zhyd.oauth.utils.StringUtils; -import me.zhyd.oauth.utils.UrlBuilder; -import me.zhyd.oauth.utils.UuidUtils; +import me.zhyd.oauth.utils.*; + +import java.util.List; /** * 默认的request处理类 @@ -267,4 +267,33 @@ public abstract class AuthDefaultRequest implements AuthRequest { return new HttpUtils(config.getHttpConfig()).get(revokeUrl(authToken)); } + /** + * 获取以 {@code separator}分割过后的 scope 信息 + * + * @param separator 多个 {@code scope} 间的分隔符 + * @param encode 是否 encode 编码 + * @param defaultScopes 默认的 scope, 当客户端没有配置 {@code scopes} 时启用 + * @return String + * @since 1.16.7 + */ + protected String getScopes(String separator, boolean encode, List defaultScopes) { + if (null == separator) { + // 默认为空格 + separator = " "; + } + List scopes = config.getScopes(); + if (null == scopes || scopes.isEmpty()) { + if (null == defaultScopes || defaultScopes.isEmpty()) { + return null; + } + scopes = defaultScopes; + } + StringBuilder res = new StringBuilder(); + for (AuthScope scope : scopes) { + res.append(scope.getScope()).append(separator); + } + String scopeStr = res.deleteCharAt(res.length() - separator.length()).toString(); + return encode ? UrlUtil.urlEncode(scopeStr) : scopeStr; + } + }