Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
justauth
JustAuth
提交
2de0ad50
J
JustAuth
项目概览
justauth
/
JustAuth
1 年多 前同步成功
通知
391
Star
15212
Fork
2708
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
JustAuth
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
2de0ad50
编写于
8月 26, 2021
作者:
智布道
👁
提交者:
Gitee
8月 26, 2021
浏览文件
操作
浏览文件
下载
差异文件
!28 添加微软中国(世纪互联)第三方登录,新增微软方式登录的redirectUri校验
Merge pull request !28 from mroldx/dev
上级
80132b69
23b7bcf4
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
269 addition
and
158 deletion
+269
-158
.github/FUNDING.yml
.github/FUNDING.yml
+12
-0
src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java
src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java
+27
-0
src/main/java/me/zhyd/oauth/request/AbstractAuthMicrosoftRequest.java
...a/me/zhyd/oauth/request/AbstractAuthMicrosoftRequest.java
+181
-0
src/main/java/me/zhyd/oauth/request/AuthMicrosoftCnRequest.java
...in/java/me/zhyd/oauth/request/AuthMicrosoftCnRequest.java
+23
-0
src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
...main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
+3
-158
src/main/java/me/zhyd/oauth/utils/AuthChecker.java
src/main/java/me/zhyd/oauth/utils/AuthChecker.java
+10
-0
src/main/java/me/zhyd/oauth/utils/GlobalAuthUtils.java
src/main/java/me/zhyd/oauth/utils/GlobalAuthUtils.java
+13
-0
未找到文件。
.github/FUNDING.yml
0 → 100644
浏览文件 @
2de0ad50
# These are supported funding model platforms
github
:
# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon
:
# Replace with a single Patreon username
open_collective
:
# Replace with a single Open Collective username
ko_fi
:
# Replace with a single Ko-fi username
tidelift
:
# Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge
:
# Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay
:
# Replace with a single Liberapay username
issuehunt
:
# Replace with a single IssueHunt username
otechie
:
# Replace with a single Otechie username
custom
:
[
'
https://justauth.wiki/sponsor.html'
]
src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java
浏览文件 @
2de0ad50
...
...
@@ -515,6 +515,33 @@ public enum AuthDefaultSource implements AuthSource {
return
AuthMicrosoftRequest
.
class
;
}
},
/**
* 微软中国(世纪互联)
*/
MICROSOFT_CN
{
@Override
public
String
authorize
()
{
return
"https://login.partner.microsoftonline.cn/common/oauth2/v2.0/authorize"
;
}
@Override
public
String
accessToken
()
{
return
"https://login.partner.microsoftonline.cn/common/oauth2/v2.0/token"
;
}
@Override
public
String
userInfo
()
{
return
"https://microsoftgraph.chinacloudapi.cn/v1.0/me"
;
}
@Override
public
String
refresh
()
{
return
"https://login.partner.microsoftonline.cn/common/oauth2/v2.0/token"
;
}
@Override
public
Class
<?
extends
AuthDefaultRequest
>
getTargetClass
()
{
return
AuthMicrosoftCnRequest
.
class
;
}
},
/**
* 小米
*/
...
...
src/main/java/me/zhyd/oauth/request/AbstractAuthMicrosoftRequest.java
0 → 100644
浏览文件 @
2de0ad50
package
me.zhyd.oauth.request
;
import
com.alibaba.fastjson.JSONObject
;
import
com.xkcoding.http.support.HttpHeader
;
import
com.xkcoding.http.util.MapUtil
;
import
me.zhyd.oauth.cache.AuthStateCache
;
import
me.zhyd.oauth.config.AuthConfig
;
import
me.zhyd.oauth.config.AuthSource
;
import
me.zhyd.oauth.enums.AuthResponseStatus
;
import
me.zhyd.oauth.enums.AuthUserGender
;
import
me.zhyd.oauth.enums.scope.AuthMicrosoftScope
;
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
;
import
java.util.Map
;
/**
* 微软登录抽象类,负责处理使用微软国际和微软中国账号登录第三方网站的登录方式
*
* @author mroldx (xzfqq5201314@gmail.com)
* @since 1.16.4
*/
public
abstract
class
AbstractAuthMicrosoftRequest
extends
AuthDefaultRequest
{
public
AbstractAuthMicrosoftRequest
(
AuthConfig
config
,
AuthSource
source
)
{
super
(
config
,
source
);
}
public
AbstractAuthMicrosoftRequest
(
AuthConfig
config
,
AuthSource
source
,
AuthStateCache
authStateCache
)
{
super
(
config
,
source
,
authStateCache
);
}
@Override
protected
AuthToken
getAccessToken
(
AuthCallback
authCallback
)
{
return
getToken
(
accessTokenUrl
(
authCallback
.
getCode
()));
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private
AuthToken
getToken
(
String
accessTokenUrl
)
{
HttpHeader
httpHeader
=
new
HttpHeader
();
Map
<
String
,
String
>
form
=
MapUtil
.
parseStringToMap
(
accessTokenUrl
,
false
);
String
response
=
new
HttpUtils
(
config
.
getHttpConfig
()).
post
(
accessTokenUrl
,
form
,
httpHeader
,
false
);
JSONObject
accessTokenObject
=
JSONObject
.
parseObject
(
response
);
this
.
checkResponse
(
accessTokenObject
);
return
AuthToken
.
builder
()
.
accessToken
(
accessTokenObject
.
getString
(
"access_token"
))
.
expireIn
(
accessTokenObject
.
getIntValue
(
"expires_in"
))
.
scope
(
accessTokenObject
.
getString
(
"scope"
))
.
tokenType
(
accessTokenObject
.
getString
(
"token_type"
))
.
refreshToken
(
accessTokenObject
.
getString
(
"refresh_token"
))
.
build
();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private
void
checkResponse
(
JSONObject
object
)
{
if
(
object
.
containsKey
(
"error"
))
{
throw
new
AuthException
(
object
.
getString
(
"error_description"
));
}
}
@Override
protected
AuthUser
getUserInfo
(
AuthToken
authToken
)
{
String
token
=
authToken
.
getAccessToken
();
String
tokenType
=
authToken
.
getTokenType
();
String
jwt
=
tokenType
+
" "
+
token
;
HttpHeader
httpHeader
=
new
HttpHeader
();
httpHeader
.
add
(
"Authorization"
,
jwt
);
String
userInfo
=
new
HttpUtils
(
config
.
getHttpConfig
()).
get
(
userInfoUrl
(
authToken
),
null
,
httpHeader
,
false
);
JSONObject
object
=
JSONObject
.
parseObject
(
userInfo
);
this
.
checkResponse
(
object
);
return
AuthUser
.
builder
()
.
rawUserInfo
(
object
)
.
uuid
(
object
.
getString
(
"id"
))
.
username
(
object
.
getString
(
"userPrincipalName"
))
.
nickname
(
object
.
getString
(
"displayName"
))
.
location
(
object
.
getString
(
"officeLocation"
))
.
email
(
object
.
getString
(
"mail"
))
.
gender
(
AuthUserGender
.
UNKNOWN
)
.
token
(
authToken
)
.
source
(
source
.
toString
())
.
build
();
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public
AuthResponse
refresh
(
AuthToken
authToken
)
{
return
AuthResponse
.
builder
()
.
code
(
AuthResponseStatus
.
SUCCESS
.
getCode
())
.
data
(
getToken
(
refreshTokenUrl
(
authToken
.
getRefreshToken
())))
.
build
();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
super
.
authorize
(
state
))
.
queryParam
(
"response_mode"
,
"query"
)
.
queryParam
(
"scope"
,
this
.
getScopes
(
" "
,
true
,
AuthScopeUtils
.
getDefaultScopes
(
AuthMicrosoftScope
.
values
())))
.
build
();
}
/**
* 返回获取accessToken的url
*
* @param code 授权code
* @return 返回获取accessToken的url
*/
@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
(
"grant_type"
,
"authorization_code"
)
.
queryParam
(
"scope"
,
this
.
getScopes
(
" "
,
true
,
AuthScopeUtils
.
getDefaultScopes
(
AuthMicrosoftScope
.
values
())))
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
build
();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected
String
userInfoUrl
(
AuthToken
authToken
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
userInfo
()).
build
();
}
/**
* 返回获取accessToken的url
*
* @param refreshToken 用户授权后的token
* @return 返回获取accessToken的url
*/
@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
)
.
queryParam
(
"grant_type"
,
"refresh_token"
)
.
queryParam
(
"scope"
,
this
.
getScopes
(
" "
,
true
,
AuthScopeUtils
.
getDefaultScopes
(
AuthMicrosoftScope
.
values
())))
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
build
();
}
}
src/main/java/me/zhyd/oauth/request/AuthMicrosoftCnRequest.java
0 → 100644
浏览文件 @
2de0ad50
package
me.zhyd.oauth.request
;
import
me.zhyd.oauth.cache.AuthStateCache
;
import
me.zhyd.oauth.config.AuthConfig
;
import
me.zhyd.oauth.config.AuthDefaultSource
;
/**
* 微软中国登录(世纪华联)
*
* @author mroldx (xzfqq5201314@gmail.com)
* @since 1.16.4
*/
public
class
AuthMicrosoftCnRequest
extends
AbstractAuthMicrosoftRequest
{
public
AuthMicrosoftCnRequest
(
AuthConfig
config
)
{
super
(
config
,
AuthDefaultSource
.
MICROSOFT_CN
);
}
public
AuthMicrosoftCnRequest
(
AuthConfig
config
,
AuthStateCache
authStateCache
)
{
super
(
config
,
AuthDefaultSource
.
MICROSOFT_CN
,
authStateCache
);
}
}
src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
浏览文件 @
2de0ad50
package
me.zhyd.oauth.request
;
import
com.alibaba.fastjson.JSONObject
;
import
com.xkcoding.http.support.HttpHeader
;
import
com.xkcoding.http.util.MapUtil
;
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.AuthMicrosoftScope
;
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
;
import
java.util.Map
;
/**
* 微软登录
*
* @author yangkai.shen (https://xkcoding.com)
* @update:2021-08-24 mroldx (xzfqq5201314@gmail.com)
* @since 1.5.0
*/
public
class
AuthMicrosoftRequest
extends
AuthDefaultRequest
{
public
class
AuthMicrosoftRequest
extends
AbstractAuthMicrosoftRequest
{
public
AuthMicrosoftRequest
(
AuthConfig
config
)
{
super
(
config
,
AuthDefaultSource
.
MICROSOFT
);
}
...
...
@@ -35,145 +21,4 @@ public class AuthMicrosoftRequest extends AuthDefaultRequest {
super
(
config
,
AuthDefaultSource
.
MICROSOFT
,
authStateCache
);
}
@Override
protected
AuthToken
getAccessToken
(
AuthCallback
authCallback
)
{
return
getToken
(
accessTokenUrl
(
authCallback
.
getCode
()));
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private
AuthToken
getToken
(
String
accessTokenUrl
)
{
HttpHeader
httpHeader
=
new
HttpHeader
();
Map
<
String
,
String
>
form
=
MapUtil
.
parseStringToMap
(
accessTokenUrl
,
false
);
String
response
=
new
HttpUtils
(
config
.
getHttpConfig
()).
post
(
accessTokenUrl
,
form
,
httpHeader
,
false
);
JSONObject
accessTokenObject
=
JSONObject
.
parseObject
(
response
);
this
.
checkResponse
(
accessTokenObject
);
return
AuthToken
.
builder
()
.
accessToken
(
accessTokenObject
.
getString
(
"access_token"
))
.
expireIn
(
accessTokenObject
.
getIntValue
(
"expires_in"
))
.
scope
(
accessTokenObject
.
getString
(
"scope"
))
.
tokenType
(
accessTokenObject
.
getString
(
"token_type"
))
.
refreshToken
(
accessTokenObject
.
getString
(
"refresh_token"
))
.
build
();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private
void
checkResponse
(
JSONObject
object
)
{
if
(
object
.
containsKey
(
"error"
))
{
throw
new
AuthException
(
object
.
getString
(
"error_description"
));
}
}
@Override
protected
AuthUser
getUserInfo
(
AuthToken
authToken
)
{
String
token
=
authToken
.
getAccessToken
();
String
tokenType
=
authToken
.
getTokenType
();
String
jwt
=
tokenType
+
" "
+
token
;
HttpHeader
httpHeader
=
new
HttpHeader
();
httpHeader
.
add
(
"Authorization"
,
jwt
);
String
userInfo
=
new
HttpUtils
(
config
.
getHttpConfig
()).
get
(
userInfoUrl
(
authToken
),
null
,
httpHeader
,
false
);
JSONObject
object
=
JSONObject
.
parseObject
(
userInfo
);
this
.
checkResponse
(
object
);
return
AuthUser
.
builder
()
.
rawUserInfo
(
object
)
.
uuid
(
object
.
getString
(
"id"
))
.
username
(
object
.
getString
(
"userPrincipalName"
))
.
nickname
(
object
.
getString
(
"displayName"
))
.
location
(
object
.
getString
(
"officeLocation"
))
.
email
(
object
.
getString
(
"mail"
))
.
gender
(
AuthUserGender
.
UNKNOWN
)
.
token
(
authToken
)
.
source
(
source
.
toString
())
.
build
();
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public
AuthResponse
refresh
(
AuthToken
authToken
)
{
return
AuthResponse
.
builder
()
.
code
(
AuthResponseStatus
.
SUCCESS
.
getCode
())
.
data
(
getToken
(
refreshTokenUrl
(
authToken
.
getRefreshToken
())))
.
build
();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
super
.
authorize
(
state
))
.
queryParam
(
"response_mode"
,
"query"
)
.
queryParam
(
"scope"
,
this
.
getScopes
(
" "
,
true
,
AuthScopeUtils
.
getDefaultScopes
(
AuthMicrosoftScope
.
values
())))
.
build
();
}
/**
* 返回获取accessToken的url
*
* @param code 授权code
* @return 返回获取accessToken的url
*/
@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
(
"grant_type"
,
"authorization_code"
)
.
queryParam
(
"scope"
,
this
.
getScopes
(
" "
,
true
,
AuthScopeUtils
.
getDefaultScopes
(
AuthMicrosoftScope
.
values
())))
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
build
();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected
String
userInfoUrl
(
AuthToken
authToken
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
userInfo
()).
build
();
}
/**
* 返回获取accessToken的url
*
* @param refreshToken 用户授权后的token
* @return 返回获取accessToken的url
*/
@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
)
.
queryParam
(
"grant_type"
,
"refresh_token"
)
.
queryParam
(
"scope"
,
this
.
getScopes
(
" "
,
true
,
AuthScopeUtils
.
getDefaultScopes
(
AuthMicrosoftScope
.
values
())))
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
build
();
}
}
src/main/java/me/zhyd/oauth/utils/AuthChecker.java
浏览文件 @
2de0ad50
...
...
@@ -76,6 +76,16 @@ public class AuthChecker {
// The redirect uri of alipay is forbidden to use localhost or 127.0.0.1
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_REDIRECT_URI
,
source
);
}
// 微软的回调地址必须为https的链接或者localhost,不允许使用http
if
(
AuthDefaultSource
.
MICROSOFT
==
source
&&
!
GlobalAuthUtils
.
isHttpsProtocolOrLocalHost
(
redirectUri
)
){
// Microsoft's redirect uri must use the HTTPS or localhost
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_REDIRECT_URI
,
source
);
}
// 微软中国的回调地址必须为https的链接或者localhost,不允许使用http
if
(
AuthDefaultSource
.
MICROSOFT_CN
==
source
&&
!
GlobalAuthUtils
.
isHttpsProtocolOrLocalHost
(
redirectUri
)
){
// Microsoft's redirect uri must use the HTTPS or localhost
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_REDIRECT_URI
,
source
);
}
}
/**
...
...
src/main/java/me/zhyd/oauth/utils/GlobalAuthUtils.java
浏览文件 @
2de0ad50
...
...
@@ -175,6 +175,19 @@ public class GlobalAuthUtils {
return
StringUtils
.
isEmpty
(
url
)
||
url
.
contains
(
"127.0.0.1"
)
||
url
.
contains
(
"localhost"
);
}
/**
* 是否为https协议或本地主机(域名)
*
* @param url 待验证的url
* @return true: https协议或本地主机 false: 非https协议或本机主机
*/
public
static
boolean
isHttpsProtocolOrLocalHost
(
String
url
)
{
if
(
StringUtils
.
isEmpty
(
url
))
{
return
false
;
}
return
isHttpsProtocol
(
url
)
||
isLocalHost
(
url
);
}
/**
* Generate nonce with given length
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录