forked from justauth/JustAuth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
src/main/java/me/zhyd/oauth/enums/scope/AuthSlackScope.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package me.zhyd.oauth.enums.scope; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
/** | ||
* Slack 平台 OAuth 授权范围 | ||
* | ||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) | ||
* @since 1.16.0 | ||
*/ | ||
@Getter | ||
@AllArgsConstructor | ||
public enum AuthSlackScope implements AuthScope { | ||
|
||
/** | ||
* {@code scope} 含义,以{@code description} 为准 | ||
*/ | ||
USERS_PROFILE_READ("users.profile:read", "View profile details about people in a workspace", true), | ||
USERS_READ("users:read", "View people in a workspace", true), | ||
USERS_READ_EMAIL("users:read.email", "View email addresses of people in a workspace", true), | ||
USERS_PROFILE_WRITE("users.profile:write", "Edit a user’s profile information and status", false), | ||
USERS_PROFILE_WRITE_USER("users.profile:write:user", "Change the user's profile fields", false), | ||
USERS_WRITE("users:write", "Set presence for your slack app", false), | ||
ADMIN("admin", "Administer a workspace", false), | ||
ADMIN_ANALYTICS_READ("admin.analytics:read", "Access analytics data about the organization", false), | ||
ADMIN_APPS_READ("admin.apps:read", "View apps and app requests in a workspace", false), | ||
ADMIN_APPS_WRITE("admin.apps:write", "Manage apps in a workspace", false), | ||
ADMIN_BARRIERS_READ("admin.barriers:read", "Read information barriers in the organization", false), | ||
ADMIN_BARRIERS_WRITE("admin.barriers:write", "Manage information barriers in the organization", false), | ||
ADMIN_CONVERSATIONS_READ("admin.conversations:read", "View the channel’s member list, topic, purpose and channel name", false), | ||
ADMIN_CONVERSATIONS_WRITE("admin.conversations:write", "Start a new conversation, modify a conversation and modify channel details", false), | ||
ADMIN_INVITES_READ("admin.invites:read", "Gain information about invite requests in a Grid organization.", false), | ||
ADMIN_INVITES_WRITE("admin.invites:write", "Approve or deny invite requests in a Grid organization.", false), | ||
ADMIN_TEAMS_READ("admin.teams:read", "Access information about a workspace", false), | ||
ADMIN_TEAMS_WRITE("admin.teams:write", "Make changes to a workspace", false), | ||
ADMIN_USERGROUPS_READ("admin.usergroups:read", "Access information about user groups", false), | ||
ADMIN_USERGROUPS_WRITE("admin.usergroups:write", "Make changes to your usergroups", false), | ||
ADMIN_USERS_READ("admin.users:read", "Access a workspace’s profile information", false), | ||
ADMIN_USERS_WRITE("admin.users:write", "Modify account information", false), | ||
APP_MENTIONS_READ("app_mentions:read", "View messages that directly mention @your_slack_app in conversations that the app is in", false), | ||
AUDITLOGS_READ("auditlogs:read", "View events from all workspaces, channels and users (Enterprise Grid only)", false), | ||
BOT("bot", "Add the ability for people to direct message or mention @your_slack_app", false), | ||
CALLS_READ("calls:read", "View information about ongoing and past calls", false), | ||
CALLS_WRITE("calls:write", "Start and manage calls in a workspace", false), | ||
CHANNELS_HISTORY("channels:history", "View messages and other content in public channels that your slack app has been added to", false), | ||
CHANNELS_JOIN("channels:join", "Join public channels in a workspace", false), | ||
CHANNELS_MANAGE("channels:manage", "Manage public channels that your slack app has been added to and create new ones", false), | ||
CHANNELS_READ("channels:read", "View basic information about public channels in a workspace", false), | ||
CHANNELS_WRITE("channels:write", "Manage a user’s public channels and create new ones on a user’s behalf", false), | ||
CHAT_WRITE("chat:write", "Post messages in approved channels & conversations", false), | ||
CHAT_WRITE_CUSTOMIZE("chat:write.customize", "Send messages as @your_slack_app with a customized username and avatar", false), | ||
CHAT_WRITE_PUBLIC("chat:write.public", "Send messages to channels @your_slack_app isn't a member of", false), | ||
CHAT_WRITE_BOT("chat:write:bot", "Send messages as your slack app", false), | ||
CHAT_WRITE_USER("chat:write:user", "Send messages on a user’s behalf", false), | ||
CLIENT("client", "Receive all events from a workspace in real time", false), | ||
COMMANDS("commands", "Add shortcuts and/or slash commands that people can use", false), | ||
CONVERSATIONS_HISTORY("conversations:history", "Deprecated: Retrieve conversation history for legacy workspace apps", false), | ||
CONVERSATIONS_READ("conversations:read", "Deprecated: Retrieve information on conversations for legacy workspace apps", false), | ||
CONVERSATIONS_WRITE("conversations:write", "Deprecated: Edit conversation attributes for legacy workspace apps", false), | ||
DND_READ("dnd:read", "View Do Not Disturb settings for people in a workspace", false), | ||
DND_WRITE("dnd:write", "Edit a user’s Do Not Disturb settings", false), | ||
DND_WRITE_USER("dnd:write:user", "Change the user's Do Not Disturb settings", false), | ||
EMOJI_READ("emoji:read", "View custom emoji in a workspace", false), | ||
FILES_READ("files:read", "View files shared in channels and conversations that your slack app has been added to", false), | ||
FILES_WRITE("files:write", "Upload, edit, and delete files as your slack app", false), | ||
FILES_WRITE_USER("files:write:user", "Upload, edit, and delete files as your slack app", false), | ||
GROUPS_HISTORY("groups:history", "View messages and other content in private channels that your slack app has been added to", false), | ||
GROUPS_READ("groups:read", "View basic information about private channels that your slack app has been added to", false), | ||
GROUPS_WRITE("groups:write", "Manage private channels that your slack app has been added to and create new ones", false), | ||
IDENTIFY("identify", "View information about a user’s identity", false), | ||
IDENTITY_AVATAR("identity.avatar", "View a user’s Slack avatar", false), | ||
IDENTITY_AVATAR_READ_USER("identity.avatar:read:user", "View the user's profile picture", false), | ||
IDENTITY_BASIC("identity.basic", "View information about a user’s identity", false), | ||
IDENTITY_EMAIL("identity.email", "View a user’s email address", false), | ||
IDENTITY_EMAIL_READ_USER("identity.email:read:user", "This scope is not yet described.", false), | ||
IDENTITY_TEAM("identity.team", "View a user’s Slack workspace name", false), | ||
IDENTITY_TEAM_READ_USER("identity.team:read:user", "View the workspace's name, domain, and icon", false), | ||
IDENTITY_READ_USER("identity:read:user", "This scope is not yet described.", false), | ||
IM_HISTORY("im:history", "View messages and other content in direct messages that your slack app has been added to", false), | ||
IM_READ("im:read", "View basic information about direct messages that your slack app has been added to", false), | ||
IM_WRITE("im:write", "Start direct messages with people", false), | ||
INCOMING_WEBHOOK("incoming-webhook", "Create one-way webhooks to post messages to a specific channel", false), | ||
LINKS_READ("links:read", "View URLs in messages", false), | ||
LINKS_WRITE("links:write", "Show previews of URLs in messages", false), | ||
MPIM_HISTORY("mpim:history", "View messages and other content in group direct messages that your slack app has been added to", false), | ||
MPIM_READ("mpim:read", "View basic information about group direct messages that your slack app has been added to", false), | ||
MPIM_WRITE("mpim:write", "Start group direct messages with people", false), | ||
NONE("none", "Execute methods without needing a scope", false), | ||
PINS_READ("pins:read", "View pinned content in channels and conversations that your slack app has been added to", false), | ||
PINS_WRITE("pins:write", "Add and remove pinned messages and files", false), | ||
POST("post", "Post messages to a workspace", false), | ||
REACTIONS_READ("reactions:read", "View emoji reactions and their associated content in channels and conversations that your slack app has been added to", false), | ||
REACTIONS_WRITE("reactions:write", "Add and edit emoji reactions", false), | ||
READ("read", "View all content in a workspace", false), | ||
REMINDERS_READ("reminders:read", "View reminders created by your slack app", false), | ||
REMINDERS_READ_USER("reminders:read:user", "Access reminders created by a user or for a user", false), | ||
REMINDERS_WRITE("reminders:write", "Add, remove, or mark reminders as complete", false), | ||
REMINDERS_WRITE_USER("reminders:write:user", "Add, remove, or complete reminders for the user", false), | ||
REMOTE_FILES_READ("remote_files:read", "View remote files added by the app in a workspace", false), | ||
REMOTE_FILES_SHARE("remote_files:share", "Share remote files on a user’s behalf", false), | ||
REMOTE_FILES_WRITE("remote_files:write", "Add, edit, and delete remote files on a user’s behalf", false), | ||
SEARCH_READ("search:read", "Search a workspace’s content", false), | ||
STARS_READ("stars:read", "View messages and files that your slack app has starred", false), | ||
STARS_WRITE("stars:write", "Add or remove stars", false), | ||
TEAM_READ("team:read", "View the name, email domain, and icon for workspaces your slack app is connected to", false), | ||
TOKENS_BASIC("tokens.basic", "Execute methods without needing a scope", false), | ||
USERGROUPS_READ("usergroups:read", "View user groups in a workspace", false), | ||
USERGROUPS_WRITE("usergroups:write", "Create and manage user groups", false), | ||
WORKFLOW_STEPS_EXECUTE("workflow.steps:execute", "Add steps that people can use in Workflow Builder", false); | ||
|
||
private final String scope; | ||
private final String description; | ||
private final boolean isDefault; | ||
|
||
} |
139 changes: 139 additions & 0 deletions
139
src/main/java/me/zhyd/oauth/request/AuthSlackRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package me.zhyd.oauth.request; | ||
|
||
import com.alibaba.fastjson.JSONArray; | ||
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.AuthUserGender; | ||
import me.zhyd.oauth.enums.scope.AuthSlackScope; | ||
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.AuthScopeUtils; | ||
import me.zhyd.oauth.utils.HttpUtils; | ||
import me.zhyd.oauth.utils.UrlBuilder; | ||
|
||
/** | ||
* slack登录, slack.com | ||
* | ||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) | ||
* @since 1.16.0 | ||
*/ | ||
public class AuthSlackRequest extends AuthDefaultRequest { | ||
|
||
public AuthSlackRequest(AuthConfig config) { | ||
super(config, AuthDefaultSource.SLACK); | ||
} | ||
|
||
public AuthSlackRequest(AuthConfig config, AuthStateCache authStateCache) { | ||
super(config, AuthDefaultSource.SLACK, authStateCache); | ||
} | ||
|
||
@Override | ||
protected AuthToken getAccessToken(AuthCallback authCallback) { | ||
HttpHeader header = new HttpHeader() | ||
.add("Content-Type", "application/x-www-form-urlencoded"); | ||
String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()), null, header, false); | ||
JSONObject accessTokenObject = JSONObject.parseObject(response); | ||
this.checkResponse(accessTokenObject); | ||
return AuthToken.builder() | ||
.accessToken(accessTokenObject.getString("access_token")) | ||
.scope(accessTokenObject.getString("scope")) | ||
.tokenType(accessTokenObject.getString("token_type")) | ||
.uid(accessTokenObject.getJSONObject("authed_user").getString("id")) | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected AuthUser getUserInfo(AuthToken authToken) { | ||
HttpHeader header = new HttpHeader() | ||
.add("Content-Type", "application/x-www-form-urlencoded") | ||
.add("Authorization", "Bearer ".concat(authToken.getAccessToken())); | ||
String userInfo = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, header, false); | ||
JSONObject object = JSONObject.parseObject(userInfo); | ||
this.checkResponse(object); | ||
JSONObject user = object.getJSONObject("user"); | ||
JSONObject profile = user.getJSONObject("profile"); | ||
return AuthUser.builder() | ||
.rawUserInfo(user) | ||
.uuid(user.getString("id")) | ||
.username(user.getString("name")) | ||
.nickname(user.getString("real_name")) | ||
.avatar(profile.getString("image_original")) | ||
.email(profile.getString("email")) | ||
.gender(AuthUserGender.UNKNOWN) | ||
.token(authToken) | ||
.source(source.toString()) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public AuthResponse revoke(AuthToken authToken) { | ||
HttpHeader header = new HttpHeader() | ||
.add("Content-Type", "application/x-www-form-urlencoded") | ||
.add("Authorization", "Bearer ".concat(authToken.getAccessToken())); | ||
String userInfo = new HttpUtils(config.getHttpConfig()).get(source.revoke(), null, header, false); | ||
JSONObject object = JSONObject.parseObject(userInfo); | ||
this.checkResponse(object); | ||
// 返回1表示取消授权成功,否则失败 | ||
AuthResponseStatus status = object.getBooleanValue("revoked") ? AuthResponseStatus.SUCCESS : AuthResponseStatus.FAILURE; | ||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build(); | ||
} | ||
|
||
/** | ||
* 检查响应内容是否正确 | ||
* | ||
* @param object 请求响应内容 | ||
*/ | ||
private void checkResponse(JSONObject object) { | ||
if (!object.getBooleanValue("ok")) { | ||
String errorMsg = object.getString("error"); | ||
if (object.containsKey("response_metadata")) { | ||
JSONArray array = object.getJSONObject("response_metadata").getJSONArray("messages"); | ||
if (null != array && array.size() > 0) { | ||
errorMsg += "; " + String.join(",", array.toArray(new String[0])); | ||
} | ||
} | ||
|
||
throw new AuthException(errorMsg); | ||
} | ||
} | ||
|
||
@Override | ||
public String userInfoUrl(AuthToken authToken) { | ||
return UrlBuilder.fromBaseUrl(source.userInfo()) | ||
.queryParam("user", authToken.getUid()) | ||
.build(); | ||
} | ||
|
||
/** | ||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state} | ||
* | ||
* @param state state 验证授权流程的参数,可以防止csrf | ||
* @return 返回授权地址 | ||
*/ | ||
@Override | ||
public String authorize(String state) { | ||
return UrlBuilder.fromBaseUrl(source.authorize()) | ||
.queryParam("client_id", config.getClientId()) | ||
.queryParam("state", getRealState(state)) | ||
.queryParam("redirect_uri", config.getRedirectUri()) | ||
.queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthSlackScope.values()))) | ||
.build(); | ||
} | ||
|
||
@Override | ||
protected String accessTokenUrl(String code) { | ||
return UrlBuilder.fromBaseUrl(source.accessToken()) | ||
.queryParam("code", code) | ||
.queryParam("client_id", config.getClientId()) | ||
.queryParam("client_secret", config.getClientSecret()) | ||
.queryParam("redirect_uri", config.getRedirectUri()) | ||
.build(); | ||
} | ||
} |