mirror of
https://gitee.com/yadong.zhang/JustAuth.git
synced 2026-01-07 19:31:48 +08:00
👽 集成 Okta
This commit is contained in:
parent
3753e3b9bc
commit
7a9e6214de
@ -7,8 +7,10 @@
|
||||
- 集成 Amazon 平台登录
|
||||
- 集成 Slack 平台登录
|
||||
- 集成 LINE 平台登录
|
||||
- 集成 Okta 平台登录
|
||||
- 集成钉钉账号登录
|
||||
- 修改
|
||||
- 【**重要**】 `AuthConfig`中的`codingGroupName`参数更名为`domainPrefix`,针对此类平台提供通用的配置。
|
||||
- 修改 `AuthFacebookScope` 中的默认 scope,解决 justauth-demo 项目中使用 facebook 报错的问题
|
||||
- 升级 facebook 的 api 到 v10.0 版本
|
||||
- 优化部分代码
|
||||
|
||||
@ -942,5 +942,38 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String revoke() {
|
||||
return "https://api.line.me/oauth2/v2.1/revoke";
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Okta,
|
||||
* <p>
|
||||
* 团队/组织的域名不同,此处通过配置动态组装
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
OKTA {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/userinfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String revoke() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/revoke";
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
66
src/main/java/me/zhyd/oauth/enums/scope/AuthOktaScope.java
Normal file
66
src/main/java/me/zhyd/oauth/enums/scope/AuthOktaScope.java
Normal file
@ -0,0 +1,66 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Okta 平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthOktaScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
OPENID("openid", "Signals that a request is an OpenID request.", true),
|
||||
PROFILE("profile", "The exact data varies based on what profile information you have provided, such as: name, time zone, picture, or birthday.", true),
|
||||
EMAIL("email", "This allows the app to view your email address.", true),
|
||||
ADDRESS("address", "This allows the app to view your address, such as: street address, city, state, and zip code.", true),
|
||||
PHONE("phone", "This allows the app to view your phone number.", true),
|
||||
OFFLINE_ACCESS("offline_access", "This keeps you signed in to the app, even when you are not using it.", true),
|
||||
OKTA_USERS_MANAGE("okta.users.manage", "Allows the app to create and manage users and read all profile and credential information for users", false),
|
||||
OKTA_USERS_READ("okta.users.read", "Allows the app to read any user's profile and credential information", false),
|
||||
OKTA_USERS_MANAGE_SELF("okta.users.manage.self", "Allows the app to manage the currently signed-in user's profile. Currently only supports user profile attribute updates.", false),
|
||||
OKTA_USERS_READ_SELF("okta.users.read.self", "Allows the app to read the currently signed-in user's profile and credential information", false),
|
||||
OKTA_APPS_MANAGE("okta.apps.manage", "Allows the app to create and manage Apps in your Okta organization", false),
|
||||
OKTA_APPS_READ("okta.apps.read", "Allows the app to read information about Apps in your Okta organization", false),
|
||||
OKTA_AUTHORIZATIONSERVERS_MANAGE("okta.authorizationServers.manage", "Allows the app to manage authorization servers", false),
|
||||
OKTA_AUTHORIZATIONSERVERS_READ("okta.authorizationServers.read", "Allows the app to read authorization server information", false),
|
||||
OKTA_CLIENTS_MANAGE("okta.clients.manage", "Allows the app to manage all OAuth/OIDC clients and to create new clients", false),
|
||||
OKTA_CLIENTS_READ("okta.clients.read", "Allows the app to read information for all OAuth/OIDC clients", false),
|
||||
OKTA_CLIENTS_REGISTER("okta.clients.register", "Allows the app to register (create) new OAuth/OIDC clients (but not read information about existing clients)", false),
|
||||
OKTA_EVENTHOOKS_MANAGE("okta.eventHooks.manage", "Allows the app to create and manage Event Hooks in your Okta organization", false),
|
||||
OKTA_EVENTHOOKS_READ("okta.eventHooks.read", "Allows the app to read information about Event Hooks in your Okta organization", false),
|
||||
OKTA_FACTORS_MANAGE("okta.factors.manage", "Allows the app to manage all admin operations for org factors (for example, activate, deactive, read)", false),
|
||||
OKTA_FACTORS_READ("okta.factors.read", "Allows the app to read org factors information", false),
|
||||
OKTA_GROUPS_MANAGE("okta.groups.manage", "Allows the app to manage groups in your Okta organization", false),
|
||||
OKTA_GROUPS_READ("okta.groups.read", "Allows the app to read information about groups and their members in your Okta organization", false),
|
||||
OKTA_IDPS_MANAGE("okta.idps.manage", "Allows the app to create and manage Identity Providers in your Okta organization", false),
|
||||
OKTA_IDPS_READ("okta.idps.read", "Allows the app to read information about Identity Providers in your Okta organization", false),
|
||||
OKTA_INLINEHOOKS_MANAGE("okta.inlineHooks.manage", "Allows the app to create and manage Inline Hooks in your Okta organization.", false),
|
||||
OKTA_INLINEHOOKS_READ("okta.inlineHooks.read", "Allows the app to read information about Inline Hooks in your Okta organization.", false),
|
||||
OKTA_LINKEDOBJECTS_MANAGE("okta.linkedObjects.manage", "Allows the app to manage Linked Object definitions in your Okta organization.", false),
|
||||
OKTA_LINKEDOBJECTS_READ("okta.linkedObjects.read", "Allows the app to read Linked Object definitions in your Okta organization.", false),
|
||||
OKTA_LOGS_READ("okta.logs.read", "Allows the app to read information about System Log entries in your Okta organization", false),
|
||||
OKTA_ROLES_MANAGE("okta.roles.manage", "Allows the app to create and manage Administrator Roles in your Okta organization", false),
|
||||
OKTA_ROLES_READ("okta.roles.read", "Allows the app to read information about Administrator Roles in your Okta organization", false),
|
||||
OKTA_SCHEMAS_MANAGE("okta.schemas.manage", "Allows the app to create and manage Schemas in your Okta organization", false),
|
||||
OKTA_SCHEMAS_READ("okta.schemas.read", "Allows the app to read information about Schemas in your Okta organization", false),
|
||||
OKTA_SESSIONS_MANAGE("okta.sessions.manage", "Allows the app to manage all sessions in your Okta organization", false),
|
||||
OKTA_SESSIONS_READ("okta.sessions.read", "Allows the app to read all sessions in your Okta organization", false),
|
||||
OKTA_TEMPLATES_MANAGE("okta.templates.manage", "Allows the app to manage all custom templates in your Okta organization", false),
|
||||
OKTA_TEMPLATES_READ("okta.templates.read", "Allows the app to read all custom templates in your Okta organization", false),
|
||||
OKTA_TRUSTEDORIGINS_MANAGE("okta.trustedOrigins.manage", "Allows the app to manage all Trusted Origins in your Okta organization", false),
|
||||
OKTA_TRUSTEDORIGINS_READ("okta.trustedOrigins.read", "Allows the app to read all Trusted Origins in your Okta organization", false),
|
||||
OKTA_POLICIES_MANAGE("okta.policies.manage", "Allows the app to manage Policies in your Okta organization", false),
|
||||
OKTA_POLICIES_READ("okta.policies.read", "Allows the app to read information about Policies in your Okta organization", false),;
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
159
src/main/java/me/zhyd/oauth/request/AuthOktaRequest.java
Normal file
159
src/main/java/me/zhyd/oauth/request/AuthOktaRequest.java
Normal file
@ -0,0 +1,159 @@
|
||||
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.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthOktaScope;
|
||||
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.Base64Utils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Okta 登录
|
||||
* <p>
|
||||
* https://{domainPrefix}.okta.com/oauth2/default/.well-known/oauth-authorization-server
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class AuthOktaRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthOktaRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.OKTA);
|
||||
}
|
||||
|
||||
public AuthOktaRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.OKTA, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
String tokenUrl = accessTokenUrl(authCallback.getCode());
|
||||
return getAuthToken(tokenUrl);
|
||||
}
|
||||
|
||||
private AuthToken getAuthToken(String tokenUrl) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("accept", "application/json")
|
||||
.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(tokenUrl, null, header, false);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
this.checkResponse(accessTokenObject);
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.scope(accessTokenObject.getString("scope"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.idToken(accessTokenObject.getString("id_token"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
if (null == authToken.getRefreshToken()) {
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.ILLEGAL_TOKEN.getCode())
|
||||
.msg(AuthResponseStatus.ILLEGAL_TOKEN.getMsg())
|
||||
.build();
|
||||
}
|
||||
String refreshUrl = refreshTokenUrl(authToken.getRefreshToken());
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(this.getAuthToken(refreshUrl))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Authorization", "Bearer " + authToken.getAccessToken());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), null, header, false);
|
||||
JSONObject object = JSONObject.parseObject(response);
|
||||
this.checkResponse(object);
|
||||
JSONObject address = object.getJSONObject("address");
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("sub"))
|
||||
.username(object.getString("name"))
|
||||
.nickname(object.getString("nickname"))
|
||||
.email(object.getString("email"))
|
||||
.location(null == address ? null : address.getString("street_address"))
|
||||
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse revoke(AuthToken authToken) {
|
||||
Map<String, String> params = new HashMap<>(4);
|
||||
params.put("token", authToken.getAccessToken());
|
||||
params.put("token_type_hint", "access_token");
|
||||
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret())));
|
||||
new HttpUtils(config.getHttpConfig()).post(revokeUrl(authToken), params, header, false);
|
||||
AuthResponseStatus status = AuthResponseStatus.SUCCESS;
|
||||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
|
||||
}
|
||||
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("error")) {
|
||||
throw new AuthException(object.getString("error_description"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getDomainPrefix(), config.getAuthServerId()))
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("prompt", "consent")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthOktaScope.values())))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getDomainPrefix(), config.getAuthServerId()))
|
||||
.queryParam("code", code)
|
||||
.queryParam("grant_type", "authorization_code")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String refreshTokenUrl(String refreshToken) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.refresh(), config.getDomainPrefix(), config.getAuthServerId()))
|
||||
.queryParam("refresh_token", refreshToken)
|
||||
.queryParam("grant_type", "refresh_token")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String revokeUrl(AuthToken authToken) {
|
||||
return String.format(source.revoke(), config.getDomainPrefix(), config.getAuthServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfoUrl(AuthToken authToken) {
|
||||
return String.format(source.userInfo(), config.getDomainPrefix(), config.getAuthServerId());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user