From eaafd498901c27fb512581754082329139afa825 Mon Sep 17 00:00:00 2001 From: xiangqian Date: Mon, 22 Jul 2024 21:40:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=9B=86=E6=88=90figma=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zhyd/oauth/config/AuthDefaultSource.java | 28 ++++- .../oauth/enums/scope/AuthFigmaScope.java | 29 +++++ .../zhyd/oauth/request/AuthFigmaRequest.java | 118 ++++++++++++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/main/java/me/zhyd/oauth/enums/scope/AuthFigmaScope.java create mode 100644 src/main/java/me/zhyd/oauth/request/AuthFigmaRequest.java diff --git a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java index 35b835a..5800d3b 100644 --- a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java +++ b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java @@ -1296,6 +1296,32 @@ public enum AuthDefaultSource implements AuthSource { public Class getTargetClass() { return AuthProginnRequest.class; } - } + }, + + FIGMA{ + @Override + public String authorize() { + return "https://www.figma.com/oauth"; + } + + @Override + public String accessToken() { + return "https://www.figma.com/api/oauth/token"; + } + + @Override + public String userInfo() { + return "https://api.figma.com/v1/me"; + } + @Override + public String refresh() { + return "https://www.figma.com/api/oauth/refresh"; + } + + @Override + public Class getTargetClass() { + return null; + } + } } diff --git a/src/main/java/me/zhyd/oauth/enums/scope/AuthFigmaScope.java b/src/main/java/me/zhyd/oauth/enums/scope/AuthFigmaScope.java new file mode 100644 index 0000000..462a9a1 --- /dev/null +++ b/src/main/java/me/zhyd/oauth/enums/scope/AuthFigmaScope.java @@ -0,0 +1,29 @@ +package me.zhyd.oauth.enums.scope; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Figma OAuth 授权范围 + * ... + * + * @author xiangqian + * @since 1.16.6 + */ +@Getter +@AllArgsConstructor +public enum AuthFigmaScope implements AuthScope { + + FILE_CONTENT("files:read", "Read files, projects, users, versions, comments, components & styles, and webhooks", true), + VARIABLES("file_variables:read,file_variables:write", "Read and write to variables in Figma file. Note: this is only available to members in Enterprise organizations", false), + COMMENTS("file_comments:write", "Post and delete comments and comment reactions in files", false), + DEV_RESOURCES("file_dev_resources:read,file_dev_resources:write", "Read and write to dev resources in files", false), + LIBRARY_ANALYTICS("library_analytics:read", "Read your design system analytics", false), + WEBHOOKS("webhooks:write", "Create and manage webhooks", false); + + private final String scope; + private final String description; + private final boolean isDefault; + + +} diff --git a/src/main/java/me/zhyd/oauth/request/AuthFigmaRequest.java b/src/main/java/me/zhyd/oauth/request/AuthFigmaRequest.java new file mode 100644 index 0000000..c5f0efa --- /dev/null +++ b/src/main/java/me/zhyd/oauth/request/AuthFigmaRequest.java @@ -0,0 +1,118 @@ +package me.zhyd.oauth.request; + +import com.alibaba.fastjson.JSONObject; +import com.xkcoding.http.support.HttpHeader; +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.scope.AuthFigmaScope; +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.*; + +/** + * Figma登录 + * @author xiangqian + * @since 1.16.6 + */ +public class AuthFigmaRequest extends AuthDefaultRequest { + public AuthFigmaRequest(AuthConfig config) { + super(config, AuthDefaultSource.FIGMA); + } + + public AuthFigmaRequest(AuthConfig config, AuthStateCache authStateCache) { + super(config, AuthDefaultSource.FIGMA, authStateCache); + } + + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(super.authorize(state)) + .queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthFigmaScope.values()))) + .build(); + } + + @Override + protected AuthToken getAccessToken(AuthCallback authCallback) { + HttpHeader header = new HttpHeader() + .add("content-type", "application/x-www-form-urlencoded") + .add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret()))); + + String response = new HttpUtils(config.getHttpConfig()).post(super.accessTokenUrl(authCallback.getCode()), null, header, true).getBody(); + JSONObject accessTokenObject = JSONObject.parseObject(response); + + this.checkResponse(accessTokenObject); + + return AuthToken.builder() + .accessToken(accessTokenObject.getString("access_token")) + .refreshToken(accessTokenObject.getString("refresh_token")) + .scope(accessTokenObject.getString("scope")) + .userId(accessTokenObject.getString("user_id")) + .expireIn(accessTokenObject.getIntValue("expires_in")) + .build(); + } + + @Override + public AuthResponse refresh(AuthToken authToken) { + HttpHeader header = new HttpHeader().add("content-type", "application/x-www-form-urlencoded"); + String response = new HttpUtils(config.getHttpConfig()).post(this.refreshTokenUrl(authToken.getRefreshToken()), null, header, false).getBody(); + JSONObject dataObj = JSONObject.parseObject(response); + + this.checkResponse(dataObj); + + return AuthResponse.builder() + .code(AuthResponseStatus.SUCCESS.getCode()) + .data(AuthToken.builder() + .accessToken(dataObj.getString("access_token")) + .openId(dataObj.getString("open_id")) + .expireIn(dataObj.getIntValue("expires_in")) + .refreshToken(dataObj.getString("refresh_token")) + .scope(dataObj.getString("scope")) + .build()) + .build(); + + } + + @Override + protected String refreshTokenUrl(String refreshToken) { + return UrlBuilder.fromBaseUrl(source.refresh()) + .queryParam("client_id", config.getClientId()) + .queryParam("client_secret", config.getClientSecret()) + .queryParam("refresh_token", refreshToken) + .build(); + } + + @Override + protected AuthUser getUserInfo(AuthToken authToken) { + HttpHeader header = new HttpHeader().add("Authorization", "Bearer " + authToken.getAccessToken()); + String response = new HttpUtils(config.getHttpConfig()).get(super.userInfoUrl(authToken), null, header, false).getBody(); + JSONObject dataObj = JSONObject.parseObject(response); + + this.checkResponse(dataObj); + + return AuthUser.builder() + .rawUserInfo(dataObj) + .uuid(dataObj.getString("id")) + .username(dataObj.getString("handle")) + .avatar(dataObj.getString("img_url")) + .email(dataObj.getString("email")) + .token(authToken) + .source(source.toString()) + .build(); + } + + + /** + * 校验响应结果 + * + * @param object 接口返回的结果 + */ + private void checkResponse(JSONObject object) { + if (object.containsKey("error")) { + throw new AuthException(object.getString("error") + ":" + object.getString("message")); + } + } +} -- Gitee