提交 2e64fb96 编写于 作者: 智布道's avatar 智布道 👁

🥚 集成 Slack

上级 0e8308e6
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;
}
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();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册