From 4d92794b1ab455d0c2cfd273f962e52dd3c55b48 Mon Sep 17 00:00:00 2001
From: "Yangkai.Shen" <237497819@qq.com>
Date: Tue, 28 May 2019 15:58:41 +0800
Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=A2=9E=E5=8A=A0=E5=BE=AE?=
=?UTF-8?q?=E8=BD=AF=E7=99=BB=E5=BD=95=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 8 +-
.../oauth/authorization/Authorization.java | 6 +
.../authorization/AuthorizationFactory.java | 1 +
.../authorization/MicrosoftAuthorization.java | 19 ++++
.../java/me/zhyd/oauth/consts/ApiUrl.java | 29 +++++
.../java/me/zhyd/oauth/model/AuthSource.java | 1 +
.../oauth/request/AuthMicrosoftRequest.java | 106 ++++++++++++++++++
.../java/me/zhyd/oauth/utils/UrlBuilder.java | 60 +++++++++-
.../java/me/zhyd/oauth/AuthRequestTest.java | 13 +++
9 files changed, 235 insertions(+), 8 deletions(-)
create mode 100644 src/main/java/me/zhyd/oauth/authorization/MicrosoftAuthorization.java
create mode 100644 src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
diff --git a/README.md b/README.md
index 49b8dc5..97d5798 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,6 @@
-
-------------------------------------------------------------------------------
@@ -106,6 +105,7 @@ authRequest.login("code");
| | [AuthDouyinRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthDouyinRequest.java) | 参考文档 |
| | [AuthLinkedinRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthLinkedinRequest.java) | 参考文档 |
| | [AuthCsdnRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java) | 无 |
+| | [AuthMicrosoftRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java) | 参考文档 |
_请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经下线。如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了_
@@ -208,7 +208,7 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
| | |
**QQ群**
-
+
- JustAuth交流群 (230017570):专业交流该项目
- 开源总群 (190886500):各个开源项目的都有,也有博客建设等方面的朋友。(注意,该群需付费进入,防止发垃圾广告、垃圾推广等人士)
@@ -216,6 +216,6 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
## 请喝咖啡
-| 支付宝 | 微信 |
-| :------------: | :------------: |
+| 支付宝 | 微信 |
+| :------------: | :------------: |
| | |
\ No newline at end of file
diff --git a/src/main/java/me/zhyd/oauth/authorization/Authorization.java b/src/main/java/me/zhyd/oauth/authorization/Authorization.java
index 0db3cb9..f8508c4 100644
--- a/src/main/java/me/zhyd/oauth/authorization/Authorization.java
+++ b/src/main/java/me/zhyd/oauth/authorization/Authorization.java
@@ -11,5 +11,11 @@ import me.zhyd.oauth.config.AuthConfig;
*/
public interface Authorization {
+ /**
+ * 获取授权页面地址
+ *
+ * @param config 授权基础配置
+ * @return 授权页面地址
+ */
String getAuthorizeUrl(AuthConfig config);
}
diff --git a/src/main/java/me/zhyd/oauth/authorization/AuthorizationFactory.java b/src/main/java/me/zhyd/oauth/authorization/AuthorizationFactory.java
index 83d33d8..380c798 100644
--- a/src/main/java/me/zhyd/oauth/authorization/AuthorizationFactory.java
+++ b/src/main/java/me/zhyd/oauth/authorization/AuthorizationFactory.java
@@ -69,6 +69,7 @@ public class AuthorizationFactory {
AuthorizationFactory.register(AuthSource.FACEBOOK, new FacebookAuthorization());
AuthorizationFactory.register(AuthSource.DOUYIN, new DouyinAuthorization());
AuthorizationFactory.register(AuthSource.LINKEDIN, new LinkedinAuthorization());
+ AuthorizationFactory.register(AuthSource.MICROSOFT, new MicrosoftAuthorization());
loader = true;
}
diff --git a/src/main/java/me/zhyd/oauth/authorization/MicrosoftAuthorization.java b/src/main/java/me/zhyd/oauth/authorization/MicrosoftAuthorization.java
new file mode 100644
index 0000000..4dff724
--- /dev/null
+++ b/src/main/java/me/zhyd/oauth/authorization/MicrosoftAuthorization.java
@@ -0,0 +1,19 @@
+package me.zhyd.oauth.authorization;
+
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.utils.UrlBuilder;
+
+/**
+ * 微软授权
+ *
+ * @author yangkai.shen (https://xkcoding.com)
+ * @version 1.5
+ * @since 1.5
+ */
+public class MicrosoftAuthorization implements Authorization {
+
+ @Override
+ public String getAuthorizeUrl(AuthConfig config) {
+ return UrlBuilder.getMicrosoftAuthorizeUrl(config.getClientId(), config.getRedirectUri());
+ }
+}
diff --git a/src/main/java/me/zhyd/oauth/consts/ApiUrl.java b/src/main/java/me/zhyd/oauth/consts/ApiUrl.java
index 77b617f..846ce93 100644
--- a/src/main/java/me/zhyd/oauth/consts/ApiUrl.java
+++ b/src/main/java/me/zhyd/oauth/consts/ApiUrl.java
@@ -503,6 +503,35 @@ public enum ApiUrl {
public String refresh() {
return "https://www.linkedin.com/oauth/v2/accessToken";
}
+ },
+ /**
+ * 微软
+ */
+ MICROSOFT {
+ @Override
+ public String authorize() {
+ return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
+ }
+
+ @Override
+ public String accessToken() {
+ return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
+ }
+
+ @Override
+ public String userInfo() {
+ return "https://graph.microsoft.com/v1.0/me";
+ }
+
+ @Override
+ public String revoke() {
+ throw new AuthException(ResponseStatus.UNSUPPORTED);
+ }
+
+ @Override
+ public String refresh() {
+ return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
+ }
};
/**
diff --git a/src/main/java/me/zhyd/oauth/model/AuthSource.java b/src/main/java/me/zhyd/oauth/model/AuthSource.java
index c259b06..852427c 100644
--- a/src/main/java/me/zhyd/oauth/model/AuthSource.java
+++ b/src/main/java/me/zhyd/oauth/model/AuthSource.java
@@ -25,4 +25,5 @@ public enum AuthSource {
FACEBOOK,
DOUYIN,
LINKEDIN,
+ MICROSOFT
}
diff --git a/src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java b/src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
new file mode 100644
index 0000000..dc8801e
--- /dev/null
+++ b/src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
@@ -0,0 +1,106 @@
+package me.zhyd.oauth.request;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthSource;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.utils.UrlBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 微软登录
+ *
+ * @author yangkai.shen (https://xkcoding.com)
+ * @version 1.5
+ * @since 1.5
+ */
+public class AuthMicrosoftRequest extends BaseAuthRequest {
+ public AuthMicrosoftRequest(AuthConfig config) {
+ super(config, AuthSource.MICROSOFT);
+ }
+
+ @Override
+ protected AuthToken getAccessToken(String code) {
+ String accessTokenUrl = UrlBuilder.getMicrosoftAccessTokenUrl(config.getClientId(), config.getClientSecret(), config
+ .getRedirectUri(), code);
+
+ return getToken(accessTokenUrl);
+ }
+
+ /**
+ * 获取token,适用于获取access_token和刷新token
+ *
+ * @param accessTokenUrl 实际请求token的地址
+ * @return token对象
+ */
+ private AuthToken getToken(String accessTokenUrl) {
+ Map paramMap = new HashMap<>(6);
+ HttpUtil.decodeParamMap(accessTokenUrl, "UTF-8").forEach(paramMap::put);
+ HttpResponse response = HttpRequest.post(accessTokenUrl)
+ .header("Host", "https://login.microsoftonline.com")
+ .header("Content-Type", "application/x-www-form-urlencoded")
+ .form(paramMap)
+ .execute();
+ String accessTokenStr = response.body();
+ JSONObject object = JSONObject.parseObject(accessTokenStr);
+
+ this.checkResponse(object);
+
+ return AuthToken.builder()
+ .accessToken(object.getString("access_token"))
+ .expireIn(object.getIntValue("expires_in"))
+ .scope(object.getString("scope"))
+ .tokenType(object.getString("token_type"))
+ .refreshToken(object.getString("refresh_token"))
+ .build();
+ }
+
+ private void checkResponse(JSONObject response) {
+ if (response.containsKey("error")) {
+ throw new AuthException(response.getString("error_description"));
+ }
+ }
+
+ @Override
+ protected AuthUser getUserInfo(AuthToken authToken) {
+ String token = authToken.getAccessToken();
+ String tokenType = authToken.getTokenType();
+ String jwt = tokenType + " " + token;
+ HttpResponse response = HttpRequest.get(UrlBuilder.getMicrosoftUserInfoUrl())
+ .header("Authorization", jwt)
+ .execute();
+ String userInfo = response.body();
+ JSONObject object = JSONObject.parseObject(userInfo);
+ return AuthUser.builder()
+ .uuid(object.getString("id"))
+ .username(object.getString("userPrincipalName"))
+ .nickname(object.getString("displayName"))
+ .location(object.getString("officeLocation"))
+ .email(object.getString("mail"))
+ .token(authToken)
+ .source(AuthSource.MICROSOFT)
+ .build();
+ }
+
+ /**
+ * 刷新access token (续期)
+ *
+ * @param authToken 登录成功后返回的Token信息
+ * @return AuthResponse
+ */
+ @Override
+ public AuthResponse refresh(AuthToken authToken) {
+ String refreshTokenUrl = UrlBuilder.getMicrosoftRefreshUrl(config.getClientId(), config.getClientSecret(), config
+ .getRedirectUri(), authToken.getRefreshToken());
+
+ return AuthResponse.builder().code(ResponseStatus.SUCCESS.getCode()).data(getToken(refreshTokenUrl)).build();
+ }
+}
diff --git a/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java b/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java
index 91ace18..91996b7 100644
--- a/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java
+++ b/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java
@@ -620,8 +620,6 @@ public class UrlBuilder {
return MessageFormat.format(DOUYIN_REFRESH_TOKEN_PATTERN, ApiUrl.DOUYIN.refresh(), clientId, refreshToken);
}
-
-
private static final String LINKEDIN_AUTHORIZE_PATTERN = "{0}?client_id={1}&redirect_uri={2}&state={3}&response_type=code&scope=r_liteprofile%20r_emailaddress%20w_member_social";
private static final String LINKEDIN_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&code={3}&redirect_uri={4}&grant_type=authorization_code";
private static final String LINKEDIN_USER_INFO_PATTERN = "{0}?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))";
@@ -635,7 +633,8 @@ public class UrlBuilder {
* @return full url
*/
public static String getLinkedinAuthorizeUrl(String clientId, String redirectUrl) {
- return MessageFormat.format(LINKEDIN_AUTHORIZE_PATTERN, ApiUrl.LINKEDIN.authorize(), clientId, redirectUrl, System.currentTimeMillis());
+ return MessageFormat.format(LINKEDIN_AUTHORIZE_PATTERN, ApiUrl.LINKEDIN.authorize(), clientId, redirectUrl, System
+ .currentTimeMillis());
}
/**
@@ -644,7 +643,7 @@ public class UrlBuilder {
* @param clientId Linkedin 应用的Client ID
* @param clientSecret Linkedin 应用的Client Secret
* @param code Linkedin 授权前的code,用来换token
- * @param redirectUrl google 应用授权成功后的回调地址
+ * @param redirectUrl google 应用授权成功后的回调地址
* @return full url
*/
public static String getLinkedinAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUrl) {
@@ -671,4 +670,57 @@ public class UrlBuilder {
public static String getLinkedinRefreshUrl(String clientId, String clientSecret, String refreshToken) {
return MessageFormat.format(LINKEDIN_REFRESH_TOKEN_PATTERN, ApiUrl.LINKEDIN.refresh(), clientId, clientSecret, refreshToken);
}
+
+
+ private static final String MICROSOFT_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&response_mode=query&scope=offline_access%20user.read%20mail.read&state={3}";
+ private static final String MICROSOFT_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&scope=user.read%20mail.read&redirect_uri={3}&code={4}&grant_type=authorization_code";
+ private static final String MICROSOFT_USER_INFO_PATTERN = "{0}";
+ private static final String MICROSOFT_REFRESH_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&scope=user.read%20mail.read&redirect_uri={3}&refresh_token={4}&grant_type=refresh_token";
+
+ /**
+ * 获取微软授权地址
+ *
+ * @param clientId 微软 应用的Client ID
+ * @param redirectUrl 微软 应用授权成功后的回调地址
+ * @return full url
+ */
+ public static String getMicrosoftAuthorizeUrl(String clientId, String redirectUrl) {
+ return MessageFormat.format(MICROSOFT_AUTHORIZE_PATTERN, ApiUrl.MICROSOFT.authorize(), clientId, redirectUrl, System
+ .currentTimeMillis());
+ }
+
+ /**
+ * 获取微软 token的接口地址
+ *
+ * @param clientId 微软 应用的Client ID
+ * @param clientSecret 微软 应用的Client Secret
+ * @param redirectUrl 微软 应用授权成功后的回调地址
+ * @param code 微软 授权前的code,用来换token
+ * @return full url
+ */
+ public static String getMicrosoftAccessTokenUrl(String clientId, String clientSecret,String redirectUrl, String code) {
+ return MessageFormat.format(MICROSOFT_ACCESS_TOKEN_PATTERN, ApiUrl.MICROSOFT.accessToken(), clientId, clientSecret, redirectUrl, code);
+ }
+
+ /**
+ * 获取微软用户详情的接口地址
+ *
+ * @return full url
+ */
+ public static String getMicrosoftUserInfoUrl() {
+ return MessageFormat.format(MICROSOFT_USER_INFO_PATTERN, ApiUrl.MICROSOFT.userInfo());
+ }
+
+ /**
+ * 获取微软 刷新令牌 地址
+ *
+ * @param clientId 微软应用的client_key
+ * @param clientSecret 微软 应用的Client Secret
+ * @param redirectUrl 微软 应用授权成功后的回调地址
+ * @param refreshToken 微软应用返回的refresh_token
+ * @return full url
+ */
+ public static String getMicrosoftRefreshUrl(String clientId, String clientSecret, String redirectUrl, String refreshToken) {
+ return MessageFormat.format(MICROSOFT_REFRESH_TOKEN_PATTERN, ApiUrl.MICROSOFT.refresh(), clientId, clientSecret, redirectUrl, refreshToken);
+ }
}
diff --git a/src/test/java/me/zhyd/oauth/AuthRequestTest.java b/src/test/java/me/zhyd/oauth/AuthRequestTest.java
index 4f57d26..c375537 100644
--- a/src/test/java/me/zhyd/oauth/AuthRequestTest.java
+++ b/src/test/java/me/zhyd/oauth/AuthRequestTest.java
@@ -167,4 +167,17 @@ public class AuthRequestTest {
// 授权登录后会返回一个code,用这个code进行登录
AuthResponse login = authRequest.login("code");
}
+
+ @Test
+ public void microsoftTest() {
+ AuthRequest authRequest = new AuthMicrosoftRequest(AuthConfig.builder()
+ .clientId("clientId")
+ .clientSecret("clientSecret")
+ .redirectUri("redirectUri")
+ .build());
+ // 返回授权页面,可自行调整
+ String url = authRequest.authorize();
+ // 授权登录后会返回一个code,用这个code进行登录
+ AuthResponse login = authRequest.login("code");
+ }
}
--
GitLab