Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
justauth
JustAuth
提交
8e99e545
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看板
提交
8e99e545
编写于
7月 30, 2019
作者:
智布道
👁
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'dev'
上级
094c2979
33076971
变更
57
展开全部
隐藏空白更改
内联
并排
Showing
57 changed file
with
825 addition
and
762 deletion
+825
-762
README.md
README.md
+11
-6
pom.xml
pom.xml
+1
-1
src/main/java/me/zhyd/oauth/cache/AuthCache.java
src/main/java/me/zhyd/oauth/cache/AuthCache.java
+50
-0
src/main/java/me/zhyd/oauth/cache/AuthCacheScheduler.java
src/main/java/me/zhyd/oauth/cache/AuthCacheScheduler.java
+39
-0
src/main/java/me/zhyd/oauth/cache/AuthDefaultCache.java
src/main/java/me/zhyd/oauth/cache/AuthDefaultCache.java
+144
-0
src/main/java/me/zhyd/oauth/cache/AuthStateCache.java
src/main/java/me/zhyd/oauth/cache/AuthStateCache.java
+51
-0
src/main/java/me/zhyd/oauth/config/AuthConfig.java
src/main/java/me/zhyd/oauth/config/AuthConfig.java
+0
-8
src/main/java/me/zhyd/oauth/config/AuthSource.java
src/main/java/me/zhyd/oauth/config/AuthSource.java
+0
-1
src/main/java/me/zhyd/oauth/enums/AuthToutiaoErrorCode.java
src/main/java/me/zhyd/oauth/enums/AuthToutiaoErrorCode.java
+0
-1
src/main/java/me/zhyd/oauth/enums/AuthUserGender.java
src/main/java/me/zhyd/oauth/enums/AuthUserGender.java
+0
-1
src/main/java/me/zhyd/oauth/exception/AuthException.java
src/main/java/me/zhyd/oauth/exception/AuthException.java
+0
-1
src/main/java/me/zhyd/oauth/model/AuthCallback.java
src/main/java/me/zhyd/oauth/model/AuthCallback.java
+12
-2
src/main/java/me/zhyd/oauth/model/AuthResponse.java
src/main/java/me/zhyd/oauth/model/AuthResponse.java
+0
-1
src/main/java/me/zhyd/oauth/model/AuthResponseStatus.java
src/main/java/me/zhyd/oauth/model/AuthResponseStatus.java
+0
-1
src/main/java/me/zhyd/oauth/model/AuthToken.java
src/main/java/me/zhyd/oauth/model/AuthToken.java
+0
-1
src/main/java/me/zhyd/oauth/model/AuthUser.java
src/main/java/me/zhyd/oauth/model/AuthUser.java
+2
-1
src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java
src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java
src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java
src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java
+7
-6
src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java
src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java
+1
-2
src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java
src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java
+32
-8
src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java
src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthDouyinRequest.java
src/main/java/me/zhyd/oauth/request/AuthDouyinRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthFacebookRequest.java
src/main/java/me/zhyd/oauth/request/AuthFacebookRequest.java
+1
-2
src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java
src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java
+1
-2
src/main/java/me/zhyd/oauth/request/AuthGithubRequest.java
src/main/java/me/zhyd/oauth/request/AuthGithubRequest.java
+1
-10
src/main/java/me/zhyd/oauth/request/AuthGoogleRequest.java
src/main/java/me/zhyd/oauth/request/AuthGoogleRequest.java
+6
-6
src/main/java/me/zhyd/oauth/request/AuthLinkedinRequest.java
src/main/java/me/zhyd/oauth/request/AuthLinkedinRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthMiRequest.java
src/main/java/me/zhyd/oauth/request/AuthMiRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
...main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java
src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java
+2
-3
src/main/java/me/zhyd/oauth/request/AuthPinterestRequest.java
...main/java/me/zhyd/oauth/request/AuthPinterestRequest.java
+10
-4
src/main/java/me/zhyd/oauth/request/AuthQqRequest.java
src/main/java/me/zhyd/oauth/request/AuthQqRequest.java
+8
-2
src/main/java/me/zhyd/oauth/request/AuthRenrenRequest.java
src/main/java/me/zhyd/oauth/request/AuthRenrenRequest.java
+1
-2
src/main/java/me/zhyd/oauth/request/AuthRequest.java
src/main/java/me/zhyd/oauth/request/AuthRequest.java
+15
-2
src/main/java/me/zhyd/oauth/request/AuthStackOverflowRequest.java
.../java/me/zhyd/oauth/request/AuthStackOverflowRequest.java
+10
-4
src/main/java/me/zhyd/oauth/request/AuthTaobaoRequest.java
src/main/java/me/zhyd/oauth/request/AuthTaobaoRequest.java
+7
-6
src/main/java/me/zhyd/oauth/request/AuthTeambitionRequest.java
...ain/java/me/zhyd/oauth/request/AuthTeambitionRequest.java
+1
-2
src/main/java/me/zhyd/oauth/request/AuthTencentCloudRequest.java
...n/java/me/zhyd/oauth/request/AuthTencentCloudRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthToutiaoRequest.java
src/main/java/me/zhyd/oauth/request/AuthToutiaoRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java
src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java
+6
-5
src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java
src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java
+2
-3
src/main/java/me/zhyd/oauth/utils/AuthChecker.java
src/main/java/me/zhyd/oauth/utils/AuthChecker.java
+4
-23
src/main/java/me/zhyd/oauth/utils/AuthState.java
src/main/java/me/zhyd/oauth/utils/AuthState.java
+0
-230
src/main/java/me/zhyd/oauth/utils/AuthStateUtils.java
src/main/java/me/zhyd/oauth/utils/AuthStateUtils.java
+19
-0
src/main/java/me/zhyd/oauth/utils/GlobalAuthUtil.java
src/main/java/me/zhyd/oauth/utils/GlobalAuthUtil.java
+1
-2
src/main/java/me/zhyd/oauth/utils/IpUtils.java
src/main/java/me/zhyd/oauth/utils/IpUtils.java
+3
-4
src/main/java/me/zhyd/oauth/utils/StringUtils.java
src/main/java/me/zhyd/oauth/utils/StringUtils.java
+24
-2
src/main/java/me/zhyd/oauth/utils/UrlBuilder.java
src/main/java/me/zhyd/oauth/utils/UrlBuilder.java
+2
-3
src/main/java/me/zhyd/oauth/utils/UuidUtils.java
src/main/java/me/zhyd/oauth/utils/UuidUtils.java
+65
-0
src/test/java/me/zhyd/oauth/AuthRequestTest.java
src/test/java/me/zhyd/oauth/AuthRequestTest.java
+134
-116
src/test/java/me/zhyd/oauth/cache/AuthStateCacheTest.java
src/test/java/me/zhyd/oauth/cache/AuthStateCacheTest.java
+32
-0
src/test/java/me/zhyd/oauth/utils/AuthStateTest.java
src/test/java/me/zhyd/oauth/utils/AuthStateTest.java
+0
-231
src/test/java/me/zhyd/oauth/utils/CustomTest.java
src/test/java/me/zhyd/oauth/utils/CustomTest.java
+3
-6
src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java
src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java
+30
-5
src/test/java/me/zhyd/oauth/utils/UuidUtilsTest.java
src/test/java/me/zhyd/oauth/utils/UuidUtilsTest.java
+13
-0
update.md
update.md
+20
-1
未找到文件。
README.md
浏览文件 @
8e99e545
...
...
@@ -6,7 +6,7 @@
</p>
<p
align=
"center"
>
<a
target=
"_blank"
href=
"https://search.maven.org/search?q=JustAuth"
>
<img
src=
"https://img.shields.io/badge/Maven Central-1.9.
2
-blue.svg"
></img>
<img
src=
"https://img.shields.io/badge/Maven Central-1.9.
3
-blue.svg"
></img>
</a>
<a
target=
"_blank"
href=
"https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE"
>
<img
src=
"https://img.shields.io/apm/l/vim-mode.svg?color=yellow"
></img>
...
...
@@ -15,7 +15,7 @@
<img
src=
"https://img.shields.io/badge/JDK-1.8+-green.svg"
></img>
</a>
<a
target=
"_blank"
href=
"https://apidoc.gitee.com/yadong.zhang/JustAuth/"
>
<img
src=
"https://img.shields.io/badge/Docs-1.9.
2
-orange.svg"
></img>
<img
src=
"https://img.shields.io/badge/Docs-1.9.
3
-orange.svg"
></img>
</a>
</p>
...
...
@@ -76,7 +76,7 @@ JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具
<dependency>
<groupId>
me.zhyd.oauth
</groupId>
<artifactId>
JustAuth
</artifactId>
<version>
1.9.
2
</version>
<version>
1.9.
3
</version>
</dependency>
```
-
调用api
...
...
@@ -91,14 +91,19 @@ AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
// 生成授权页面
authRequest
.
authorize
();
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
authRequest
.
login
(
callback
);
```
注:
`1.8.0`
版本后,增加了
`state`
参数校验,用于防止
[
CSRF
](
https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0
)
。强烈建议,保证单次流程内
`state`
的唯一性,且每个
`state`
只可用一次。
**配套Demo**
:
-
[
Springboot版
](
https://gitee.com/yadong.zhang/JustAuth-demo
)
-
[
jFinal版
](
https://github.com/zhangyd-c/jfinal-justauth-demo
)
-
[
jFinal版
](
https://github.com/xkcoding/jfinal-justauth-demo
)
-
[
ActFramework版
](
https://github.com/xkcoding/act-justauth-demo
)
**扩展工具**
-
[
justauth-spring-boot-starter
](
https://github.com/xkcoding/justauth-spring-boot-starter
)
: Spring Boot 集成 JustAuth 的最佳实践
**配套SpringBoot starter**
:
...
...
pom.xml
浏览文件 @
8e99e545
...
...
@@ -54,7 +54,7 @@
<maven-source.version>
2.2.1
</maven-source.version>
<maven-compiler.version>
3.7.0
</maven-compiler.version>
<maven.test.skip>
true
</maven.test.skip>
<hutool-version>
4.
5.15
</hutool-version>
<hutool-version>
4.
6.0
</hutool-version>
<lombok-version>
1.18.4
</lombok-version>
<junit-version>
4.11
</junit-version>
<fastjson-version>
1.2.58
</fastjson-version>
...
...
src/main/java/me/zhyd/oauth/cache/AuthCache.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.cache
;
/**
* JustAuth缓存,用来缓存State
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.9.3
*/
public
interface
AuthCache
{
/**
* 设置缓存
*
* @param key 缓存KEY
* @param value 缓存内容
*/
void
set
(
String
key
,
String
value
);
/**
* 设置缓存,指定过期时间
*
* @param key 缓存KEY
* @param value 缓存内容
* @param timeout 指定缓存过期时间(毫秒)
*/
void
set
(
String
key
,
String
value
,
long
timeout
);
/**
* 获取缓存
*
* @param key 缓存KEY
* @return 缓存内容
*/
String
get
(
String
key
);
/**
* 是否存在key,如果对应key的value值已过期,也返回false
*
* @param key 缓存KEY
* @return true:存在key,并且value没过期;false:key不存在或者已过期
*/
boolean
containsKey
(
String
key
);
/**
* 清理过期的缓存
*/
default
void
pruneCache
()
{
}
}
src/main/java/me/zhyd/oauth/cache/AuthCacheScheduler.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.cache
;
import
java.util.concurrent.ScheduledExecutorService
;
import
java.util.concurrent.ScheduledThreadPoolExecutor
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicInteger
;
/**
* 缓存调度器
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.9.3
*/
public
enum
AuthCacheScheduler
{
INSTANCE
;
private
AtomicInteger
cacheTaskNumber
=
new
AtomicInteger
(
1
);
private
ScheduledExecutorService
scheduler
;
AuthCacheScheduler
()
{
create
();
}
private
void
create
()
{
this
.
shutdown
();
this
.
scheduler
=
new
ScheduledThreadPoolExecutor
(
10
,
r
->
new
Thread
(
r
,
String
.
format
(
"JustAuth-Task-%s"
,
cacheTaskNumber
.
getAndIncrement
())));
}
private
void
shutdown
()
{
if
(
null
!=
scheduler
)
{
this
.
scheduler
.
shutdown
();
}
}
public
void
schedule
(
Runnable
task
,
long
delay
)
{
this
.
scheduler
.
scheduleAtFixedRate
(
task
,
delay
,
delay
,
TimeUnit
.
MILLISECONDS
);
}
}
src/main/java/me/zhyd/oauth/cache/AuthDefaultCache.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.cache
;
import
lombok.Getter
;
import
lombok.Setter
;
import
java.io.Serializable
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.locks.Lock
;
import
java.util.concurrent.locks.ReentrantReadWriteLock
;
/**
* 默认的缓存实现
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.9.3
*/
public
class
AuthDefaultCache
implements
AuthCache
{
/**
* 默认缓存过期时间:3分钟
* 鉴于授权过程中,根据个人的操作习惯,或者授权平台的不同(google等),每个授权流程的耗时也有差异,不过单个授权流程一般不会太长
* 本缓存工具默认的过期时间设置为3分钟,即程序默认认为3分钟内的授权有效,超过3分钟则默认失效,失效后删除
*/
private
static
final
long
DEF_TIMEOUT
=
3
*
60
*
1000
;
/**
* state cache
*/
private
static
Map
<
String
,
CacheState
>
stateCache
=
new
ConcurrentHashMap
<>();
private
final
ReentrantReadWriteLock
cacheLock
=
new
ReentrantReadWriteLock
(
true
);
private
final
Lock
writeLock
=
cacheLock
.
writeLock
();
private
final
Lock
readLock
=
cacheLock
.
readLock
();
public
AuthDefaultCache
()
{
this
.
schedulePrune
(
DEF_TIMEOUT
);
}
/**
* 设置缓存
*
* @param key 缓存KEY
* @param value 缓存内容
*/
@Override
public
void
set
(
String
key
,
String
value
)
{
set
(
key
,
value
,
DEF_TIMEOUT
);
}
/**
* 设置缓存
*
* @param key 缓存KEY
* @param value 缓存内容
* @param timeout 指定缓存过期时间(毫秒)
*/
@Override
public
void
set
(
String
key
,
String
value
,
long
timeout
)
{
writeLock
.
lock
();
try
{
stateCache
.
put
(
key
,
new
CacheState
(
value
,
timeout
));
}
finally
{
writeLock
.
unlock
();
}
}
/**
* 获取缓存
*
* @param key 缓存KEY
* @return 缓存内容
*/
@Override
public
String
get
(
String
key
)
{
readLock
.
lock
();
try
{
CacheState
cacheState
=
stateCache
.
get
(
key
);
if
(
null
==
cacheState
||
cacheState
.
isExpired
())
{
return
null
;
}
return
cacheState
.
getState
();
}
finally
{
readLock
.
unlock
();
}
}
/**
* 是否存在key,如果对应key的value值已过期,也返回false
*
* @param key 缓存KEY
* @return true:存在key,并且value没过期;false:key不存在或者已过期
*/
@Override
public
boolean
containsKey
(
String
key
)
{
readLock
.
lock
();
try
{
CacheState
cacheState
=
stateCache
.
get
(
key
);
return
null
!=
cacheState
&&
!
cacheState
.
isExpired
();
}
finally
{
readLock
.
unlock
();
}
}
/**
* 清理过期的缓存
*/
@Override
public
void
pruneCache
()
{
Iterator
<
CacheState
>
values
=
stateCache
.
values
().
iterator
();
CacheState
cacheState
;
while
(
values
.
hasNext
())
{
cacheState
=
values
.
next
();
if
(
cacheState
.
isExpired
())
{
values
.
remove
();
}
}
}
/**
* 定时清理
*
* @param delay 间隔时长,单位毫秒
*/
public
void
schedulePrune
(
long
delay
)
{
AuthCacheScheduler
.
INSTANCE
.
schedule
(
this
::
pruneCache
,
delay
);
}
@Getter
@Setter
private
class
CacheState
implements
Serializable
{
private
String
state
;
private
long
expire
;
CacheState
(
String
state
,
long
expire
)
{
this
.
state
=
state
;
// 实际过期时间等于当前时间加上有效期
this
.
expire
=
System
.
currentTimeMillis
()
+
expire
;
}
boolean
isExpired
()
{
return
System
.
currentTimeMillis
()
>
this
.
expire
;
}
}
}
src/main/java/me/zhyd/oauth/cache/AuthStateCache.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.cache
;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
public
class
AuthStateCache
{
private
static
AuthCache
authCache
=
new
AuthDefaultCache
();
/**
* 存入缓存
*
* @param key 缓存key
* @param value 缓存内容
*/
public
static
void
cache
(
String
key
,
String
value
)
{
authCache
.
set
(
key
,
value
);
}
/**
* 存入缓存
*
* @param key 缓存key
* @param value 缓存内容
* @param timeout 指定缓存过期时间(毫秒)
*/
public
static
void
cache
(
String
key
,
String
value
,
long
timeout
)
{
authCache
.
set
(
key
,
value
,
timeout
);
}
/**
* 获取缓存内容
*
* @param key 缓存key
* @return 缓存内容
*/
public
static
String
get
(
String
key
)
{
return
authCache
.
get
(
key
);
}
/**
* 是否存在key,如果对应key的value值已过期,也返回false
*
* @param key 缓存key
* @return true:存在key,并且value没过期;false:key不存在或者已过期
*/
public
static
boolean
containsKey
(
String
key
)
{
return
authCache
.
containsKey
(
key
);
}
}
src/main/java/me/zhyd/oauth/config/AuthConfig.java
浏览文件 @
8e99e545
...
...
@@ -6,7 +6,6 @@ import lombok.*;
* JustAuth配置类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
@@ -45,13 +44,6 @@ public class AuthConfig {
*/
private
boolean
unionId
;
/**
* 一个神奇的参数,最好使用随机的不可测的内容,可以用来防止CSRF攻击
* <p>
* 1.8.0版本新增参数
*/
private
String
state
;
/**
* Stack Overflow Key
* <p>
...
...
src/main/java/me/zhyd/oauth/config/AuthSource.java
浏览文件 @
8e99e545
...
...
@@ -7,7 +7,6 @@ import me.zhyd.oauth.model.AuthResponseStatus;
* 各api需要的url, 用枚举类分平台类型管理
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.0
*/
public
enum
AuthSource
{
...
...
src/main/java/me/zhyd/oauth/enums/AuthToutiaoErrorCode.java
浏览文件 @
8e99e545
...
...
@@ -7,7 +7,6 @@ import lombok.Getter;
* 今日头条授权登录时的异常状态码
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
src/main/java/me/zhyd/oauth/enums/AuthUserGender.java
浏览文件 @
8e99e545
...
...
@@ -9,7 +9,6 @@ import java.util.Arrays;
* 用户性别
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
src/main/java/me/zhyd/oauth/exception/AuthException.java
浏览文件 @
8e99e545
...
...
@@ -4,7 +4,6 @@ import me.zhyd.oauth.model.AuthResponseStatus;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
public
class
AuthException
extends
RuntimeException
{
...
...
src/main/java/me/zhyd/oauth/model/AuthCallback.java
浏览文件 @
8e99e545
...
...
@@ -2,13 +2,13 @@ package me.zhyd.oauth.model;
import
lombok.Getter
;
import
lombok.Setter
;
import
me.zhyd.oauth.cache.AuthStateCache
;
/**
* 授权回调时的参数类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.8.0
*/
@Getter
@Setter
...
...
@@ -28,4 +28,14 @@ public class AuthCallback {
* 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击
*/
private
String
state
;
/**
* 内置的检验state合法性的方法
*
* @return true: state正常;false:state不正常,可能授权时间过长导致state失效
* @since 1.9.3
*/
public
boolean
checkState
()
{
return
AuthStateCache
.
containsKey
(
this
.
state
);
}
}
src/main/java/me/zhyd/oauth/model/AuthResponse.java
浏览文件 @
8e99e545
...
...
@@ -8,7 +8,6 @@ import lombok.Setter;
* JustAuth统一授权响应类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
src/main/java/me/zhyd/oauth/model/AuthResponseStatus.java
浏览文件 @
8e99e545
...
...
@@ -5,7 +5,6 @@ import lombok.Getter;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
src/main/java/me/zhyd/oauth/model/AuthToken.java
浏览文件 @
8e99e545
...
...
@@ -9,7 +9,6 @@ import lombok.Setter;
* 授权所需的token
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
src/main/java/me/zhyd/oauth/model/AuthUser.java
浏览文件 @
8e99e545
...
...
@@ -10,7 +10,6 @@ import me.zhyd.oauth.enums.AuthUserGender;
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Getter
...
...
@@ -19,6 +18,8 @@ import me.zhyd.oauth.enums.AuthUserGender;
public
class
AuthUser
{
/**
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
*
* @since 1.3.3
*/
private
String
uuid
;
/**
...
...
src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java
浏览文件 @
8e99e545
...
...
@@ -21,8 +21,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 支付宝登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.1
*/
public
class
AuthAlipayRequest
extends
AuthDefaultRequest
{
...
...
@@ -86,17 +85,19 @@ public class AuthAlipayRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"app_id"
,
config
.
getClientId
())
.
queryParam
(
"scope"
,
"auth_user"
)
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
}
src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java
浏览文件 @
8e99e545
...
...
@@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 百度账号登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthBaiduRequest
extends
AuthDefaultRequest
{
...
...
@@ -79,18 +78,20 @@ public class AuthBaiduRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"display"
,
"popup"
)
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java
浏览文件 @
8e99e545
...
...
@@ -4,19 +4,18 @@ import cn.hutool.http.HttpResponse;
import
com.alibaba.fastjson.JSONObject
;
import
me.zhyd.oauth.config.AuthConfig
;
import
me.zhyd.oauth.config.AuthSource
;
import
me.zhyd.oauth.enums.AuthUserGender
;
import
me.zhyd.oauth.exception.AuthException
;
import
me.zhyd.oauth.model.AuthCallback
;
import
me.zhyd.oauth.model.AuthToken
;
import
me.zhyd.oauth.model.AuthUser
;
import
me.zhyd.oauth.enums.AuthUserGender
;
import
me.zhyd.oauth.utils.UrlBuilder
;
/**
* Cooding登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthCodingRequest
extends
AuthDefaultRequest
{
...
...
@@ -71,18 +70,20 @@ public class AuthCodingRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"scope"
,
"user"
)
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
}
src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java
浏览文件 @
8e99e545
...
...
@@ -14,8 +14,7 @@ import me.zhyd.oauth.model.AuthUser;
* CSDN登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
@Deprecated
public
class
AuthCsdnRequest
extends
AuthDefaultRequest
{
...
...
src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java
浏览文件 @
8e99e545
...
...
@@ -2,8 +2,8 @@ package me.zhyd.oauth.request;
import
cn.hutool.http.HttpRequest
;
import
cn.hutool.http.HttpResponse
;
import
lombok.Data
;
import
lombok.extern.slf4j.Slf4j
;
import
me.zhyd.oauth.cache.AuthStateCache
;
import
me.zhyd.oauth.config.AuthConfig
;
import
me.zhyd.oauth.config.AuthSource
;
import
me.zhyd.oauth.exception.AuthException
;
...
...
@@ -11,14 +11,14 @@ import me.zhyd.oauth.model.*;
import
me.zhyd.oauth.utils.AuthChecker
;
import
me.zhyd.oauth.utils.StringUtils
;
import
me.zhyd.oauth.utils.UrlBuilder
;
import
me.zhyd.oauth.utils.UuidUtils
;
/**
* 默认的request处理类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @author yangkai.shen (https://xkcoding.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
@Slf4j
public
abstract
class
AuthDefaultRequest
implements
AuthRequest
{
...
...
@@ -43,7 +43,6 @@ public abstract class AuthDefaultRequest implements AuthRequest {
public
AuthResponse
login
(
AuthCallback
authCallback
)
{
try
{
AuthChecker
.
checkCode
(
source
==
AuthSource
.
ALIPAY
?
authCallback
.
getAuth_code
()
:
authCallback
.
getCode
());
AuthChecker
.
checkState
(
authCallback
.
getState
(),
config
.
getState
());
AuthToken
authToken
=
this
.
getAccessToken
(
authCallback
);
AuthUser
user
=
this
.
getUserInfo
(
authToken
);
...
...
@@ -63,17 +62,34 @@ public abstract class AuthDefaultRequest implements AuthRequest {
}
/**
* 返回认证url,可自行跳转页面
* 返回授权url,可自行跳转页面
* <p>
* 不建议使用该方式获取授权地址,不带{@code state}的授权地址,容易受到csrf攻击。
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址,在回调方法中对{@code state}进行校验
*
* @return 返回授权地址
* @see AuthDefaultRequest#authorize(String)
*/
@Deprecated
@Override
public
String
authorize
()
{
return
this
.
authorize
(
null
);
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
@@ -130,13 +146,18 @@ public abstract class AuthDefaultRequest implements AuthRequest {
}
/**
* 获取state,如果为空, 则默认
去
当前日期的时间戳
* 获取state,如果为空, 则默认
取
当前日期的时间戳
*
* @param state 原始的state
* @return 返回不为null的state
*/
protected
String
getRealState
(
String
state
)
{
return
StringUtils
.
isEmpty
(
state
)
?
String
.
valueOf
(
System
.
currentTimeMillis
())
:
state
;
if
(
StringUtils
.
isEmpty
(
state
))
{
state
=
UuidUtils
.
getUUID
();
}
// 缓存state
AuthStateCache
.
cache
(
state
,
state
);
return
state
;
}
/**
...
...
@@ -165,6 +186,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
* @param authToken token封装
* @return HttpResponse
*/
@Deprecated
protected
HttpResponse
doPostUserInfo
(
AuthToken
authToken
)
{
return
HttpRequest
.
post
(
userInfoUrl
(
authToken
)).
execute
();
}
...
...
@@ -184,7 +206,9 @@ public abstract class AuthDefaultRequest implements AuthRequest {
*
* @param authToken token封装
* @return HttpResponse
* @since
*/
@Deprecated
protected
HttpResponse
doPostRevoke
(
AuthToken
authToken
)
{
return
HttpRequest
.
post
(
revokeUrl
(
authToken
)).
execute
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java
浏览文件 @
8e99e545
...
...
@@ -18,8 +18,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 钉钉登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthDingTalkRequest
extends
AuthDefaultRequest
{
...
...
@@ -58,18 +57,20 @@ public class AuthDingTalkRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"appid"
,
config
.
getClientId
())
.
queryParam
(
"scope"
,
"snsapi_login"
)
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthDouyinRequest.java
浏览文件 @
8e99e545
...
...
@@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 抖音登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.4.0
*/
public
class
AuthDouyinRequest
extends
AuthDefaultRequest
{
...
...
@@ -89,18 +88,20 @@ public class AuthDouyinRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_key"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"scope"
,
"user_info"
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthFacebookRequest.java
浏览文件 @
8e99e545
...
...
@@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* Facebook登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.3.0
*/
public
class
AuthFacebookRequest
extends
AuthDefaultRequest
{
...
...
src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java
浏览文件 @
8e99e545
...
...
@@ -14,8 +14,7 @@ import me.zhyd.oauth.model.AuthUser;
* Gitee登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthGiteeRequest
extends
AuthDefaultRequest
{
...
...
src/main/java/me/zhyd/oauth/request/AuthGithubRequest.java
浏览文件 @
8e99e545
...
...
@@ -17,8 +17,7 @@ import java.util.Map;
* Github登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthGithubRequest
extends
AuthDefaultRequest
{
...
...
@@ -63,12 +62,4 @@ public class AuthGithubRequest extends AuthDefaultRequest {
.
build
();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private
void
checkResponse
(
JSONObject
object
)
{
}
}
src/main/java/me/zhyd/oauth/request/AuthGoogleRequest.java
浏览文件 @
8e99e545
...
...
@@ -16,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* Google登录
*
* @author yangkai.shen (https://xkcoding.com)
* @version 1.3
* @since 1.3
* @since 1.3.0
*/
public
class
AuthGoogleRequest
extends
AuthDefaultRequest
{
...
...
@@ -61,19 +60,20 @@ public class AuthGoogleRequest extends AuthDefaultRequest {
}
/**
* 返回认证url,可自行跳转页面
* https://openidconnect.googleapis.com/v1/userinfo
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"scope"
,
"openid%20email%20profile"
)
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthLinkedinRequest.java
浏览文件 @
8e99e545
...
...
@@ -18,8 +18,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 领英登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.4.0
*/
public
class
AuthLinkedinRequest
extends
AuthDefaultRequest
{
...
...
@@ -182,18 +181,20 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"scope"
,
"r_liteprofile%20r_emailaddress%20w_member_social"
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthMiRequest.java
浏览文件 @
8e99e545
...
...
@@ -18,8 +18,7 @@ import java.text.MessageFormat;
* 小米登录
*
* @author yangkai.shen (https://xkcoding.com)
* @version 1.5
* @since 1.5
* @since 1.5.0
*/
@Slf4j
public
class
AuthMiRequest
extends
AuthDefaultRequest
{
...
...
@@ -109,19 +108,21 @@ public class AuthMiRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"scope"
,
"user/profile%20user/openIdV2%20user/phoneAndEmail"
)
.
queryParam
(
"skip_confirm"
,
"false"
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java
浏览文件 @
8e99e545
...
...
@@ -16,8 +16,7 @@ import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
* 微软登录
*
* @author yangkai.shen (https://xkcoding.com)
* @version 1.5
* @since 1.5
* @since 1.5.0
*/
public
class
AuthMicrosoftRequest
extends
AuthDefaultRequest
{
public
AuthMicrosoftRequest
(
AuthConfig
config
)
{
...
...
@@ -102,19 +101,21 @@ public class AuthMicrosoftRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"response_mode"
,
"query"
)
.
queryParam
(
"scope"
,
"offline_access%20user.read%20mail.read"
)
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java
浏览文件 @
8e99e545
...
...
@@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* oschina登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthOschinaRequest
extends
AuthDefaultRequest
{
...
...
@@ -59,7 +58,7 @@ public class AuthOschinaRequest extends AuthDefaultRequest {
/**
* 返回获取accessToken的url
*
* @param code
* @param code
授权回调时带回的授权码
* @return 返回获取accessToken的url
*/
@Override
...
...
src/main/java/me/zhyd/oauth/request/AuthPinterestRequest.java
浏览文件 @
8e99e545
...
...
@@ -19,8 +19,7 @@ import static me.zhyd.oauth.config.AuthSource.PINTEREST;
* Pinterest登录
*
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
* @version 1.9.0
* @since 1.8
* @since 1.9.0
*/
public
class
AuthPinterestRequest
extends
AuthDefaultRequest
{
...
...
@@ -69,14 +68,21 @@ public class AuthPinterestRequest extends AuthDefaultRequest {
return
jsonObject
.
getJSONObject
(
"60x60"
).
getString
(
"url"
);
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"scope"
,
"read_public"
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthQqRequest.java
浏览文件 @
8e99e545
...
...
@@ -20,8 +20,7 @@ import java.util.Map;
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @author yangkai.shen (https://xkcoding.com)
* @version 1.0
* @since 1.8
* @since 1.1.0
*/
public
class
AuthQqRequest
extends
AuthDefaultRequest
{
public
AuthQqRequest
(
AuthConfig
config
)
{
...
...
@@ -69,6 +68,13 @@ public class AuthQqRequest extends AuthDefaultRequest {
.
build
();
}
/**
* 获取QQ用户的OpenId,支持自定义是否启用查询unionid的功能,如果启用查询unionid的功能,
* 那就需要调用者先通过邮件申请unionid功能,参考链接 {@see http://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D}
*
* @param authToken 通过{@link AuthQqRequest#getAccessToken(AuthCallback)}获取到的{@code authToken}
* @return openId
*/
private
String
getOpenId
(
AuthToken
authToken
)
{
HttpResponse
response
=
HttpRequest
.
get
(
UrlBuilder
.
fromBaseUrl
(
"https://graph.qq.com/oauth2.0/me"
)
.
queryParam
(
"access_token"
,
authToken
.
getAccessToken
())
...
...
src/main/java/me/zhyd/oauth/request/AuthRenrenRequest.java
浏览文件 @
8e99e545
...
...
@@ -19,8 +19,7 @@ import static me.zhyd.oauth.model.AuthResponseStatus.SUCCESS;
* 人人登录
*
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
* @version 1.9.0
* @since 1.8
* @since 1.9.0
*/
public
class
AuthRenrenRequest
extends
AuthDefaultRequest
{
...
...
src/main/java/me/zhyd/oauth/request/AuthRequest.java
浏览文件 @
8e99e545
...
...
@@ -8,20 +8,33 @@ import me.zhyd.oauth.model.AuthToken;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
public
interface
AuthRequest
{
/**
* 返回认证url,可自行跳转页面
* 返回授权url,可自行跳转页面
* <p>
* 不建议使用该方式获取授权地址,不带{@code state}的授权地址,容易受到csrf攻击。
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址,在回调方法中对{@code state}进行校验
*
* @return 返回授权地址
*/
@Deprecated
default
String
authorize
()
{
throw
new
AuthException
(
AuthResponseStatus
.
NOT_IMPLEMENTED
);
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
*/
default
String
authorize
(
String
state
)
{
throw
new
AuthException
(
AuthResponseStatus
.
NOT_IMPLEMENTED
);
}
/**
* 第三方登录
*
...
...
src/main/java/me/zhyd/oauth/request/AuthStackOverflowRequest.java
浏览文件 @
8e99e545
...
...
@@ -18,8 +18,7 @@ import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
* Stack Overflow登录
*
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
* @version 1.9.0
* @since 1.8
* @since 1.9.0
*/
public
class
AuthStackOverflowRequest
extends
AuthDefaultRequest
{
...
...
@@ -67,14 +66,21 @@ public class AuthStackOverflowRequest extends AuthDefaultRequest {
.
build
();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"scope"
,
"read_inbox"
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthTaobaoRequest.java
浏览文件 @
8e99e545
...
...
@@ -4,11 +4,11 @@ import cn.hutool.http.HttpResponse;
import
com.alibaba.fastjson.JSONObject
;
import
me.zhyd.oauth.config.AuthConfig
;
import
me.zhyd.oauth.config.AuthSource
;
import
me.zhyd.oauth.enums.AuthUserGender
;
import
me.zhyd.oauth.exception.AuthException
;
import
me.zhyd.oauth.model.AuthCallback
;
import
me.zhyd.oauth.model.AuthToken
;
import
me.zhyd.oauth.model.AuthUser
;
import
me.zhyd.oauth.enums.AuthUserGender
;
import
me.zhyd.oauth.utils.GlobalAuthUtil
;
import
me.zhyd.oauth.utils.UrlBuilder
;
...
...
@@ -16,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 淘宝登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.1.0
*/
public
class
AuthTaobaoRequest
extends
AuthDefaultRequest
{
...
...
@@ -55,18 +54,20 @@ public class AuthTaobaoRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"view"
,
"web"
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
}
src/main/java/me/zhyd/oauth/request/AuthTeambitionRequest.java
浏览文件 @
8e99e545
...
...
@@ -13,8 +13,7 @@ import me.zhyd.oauth.model.*;
* Teambition授权登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.9.0
*/
public
class
AuthTeambitionRequest
extends
AuthDefaultRequest
{
...
...
src/main/java/me/zhyd/oauth/request/AuthTencentCloudRequest.java
浏览文件 @
8e99e545
...
...
@@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 腾讯云登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthTencentCloudRequest
extends
AuthDefaultRequest
{
...
...
@@ -71,18 +70,20 @@ public class AuthTencentCloudRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_id"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"scope"
,
"user"
)
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
}
src/main/java/me/zhyd/oauth/request/AuthToutiaoRequest.java
浏览文件 @
8e99e545
...
...
@@ -16,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 今日头条登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.5
* @since 1.5
* @since 1.6.0-beta
*/
public
class
AuthToutiaoRequest
extends
AuthDefaultRequest
{
...
...
@@ -65,19 +64,21 @@ public class AuthToutiaoRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"client_key"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()))
.
queryParam
(
"auth_only"
,
1
)
.
queryParam
(
"display"
,
0
)
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java
浏览文件 @
8e99e545
...
...
@@ -14,8 +14,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 微信登录
*
* @author yangkai.shen (https://xkcoding.com)
* @version 1.0
* @since 1.8
* @since 1.1.0
*/
public
class
AuthWeChatRequest
extends
AuthDefaultRequest
{
public
AuthWeChatRequest
(
AuthConfig
config
)
{
...
...
@@ -100,18 +99,20 @@ public class AuthWeChatRequest extends AuthDefaultRequest {
}
/**
* 返回
认证url,可自行跳转页面
* 返回
带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public
String
authorize
()
{
public
String
authorize
(
String
state
)
{
return
UrlBuilder
.
fromBaseUrl
(
source
.
authorize
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"appid"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"scope"
,
"snsapi_login"
)
.
queryParam
(
"state"
,
getRealState
(
config
.
getState
()).
concat
(
"#wechat_redirect"
))
.
queryParam
(
"state"
,
getRealState
(
state
))
.
build
();
}
...
...
src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java
浏览文件 @
8e99e545
...
...
@@ -19,8 +19,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
* 微博登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
AuthWeiboRequest
extends
AuthDefaultRequest
{
...
...
@@ -51,7 +50,7 @@ public class AuthWeiboRequest extends AuthDefaultRequest {
String
oauthParam
=
String
.
format
(
"uid=%s&access_token=%s"
,
uid
,
accessToken
);
HttpResponse
response
=
HttpRequest
.
get
(
userInfoUrl
(
authToken
))
.
header
(
"Authorization"
,
"OAuth2 "
+
oauthParam
)
.
header
(
"API-RemoteIP"
,
IpUtils
.
getIp
())
.
header
(
"API-RemoteIP"
,
IpUtils
.
get
Local
Ip
())
.
execute
();
String
userInfo
=
response
.
body
();
JSONObject
object
=
JSONObject
.
parseObject
(
userInfo
);
...
...
src/main/java/me/zhyd/oauth/utils/AuthChecker.java
浏览文件 @
8e99e545
...
...
@@ -9,8 +9,7 @@ import me.zhyd.oauth.model.AuthResponseStatus;
* 授权配置类的校验器
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.6.1-beta
*/
public
class
AuthChecker
{
...
...
@@ -20,6 +19,7 @@ public class AuthChecker {
* @param config config
* @param source source
* @return true or false
* @since 1.6.1-beta
*/
public
static
boolean
isSupportedAuth
(
AuthConfig
config
,
AuthSource
source
)
{
boolean
isSupported
=
StringUtils
.
isNotEmpty
(
config
.
getClientId
())
&&
StringUtils
.
isNotEmpty
(
config
.
getClientSecret
())
&&
StringUtils
.
isNotEmpty
(
config
.
getRedirectUri
());
...
...
@@ -37,6 +37,7 @@ public class AuthChecker {
*
* @param config config
* @param source source
* @since 1.6.1-beta
*/
public
static
void
checkConfig
(
AuthConfig
config
,
AuthSource
source
)
{
String
redirectUri
=
config
.
getRedirectUri
();
...
...
@@ -57,31 +58,11 @@ public class AuthChecker {
* 校验回调传回的code
*
* @param code 回调时传回的code
* @since 1.8.0
*/
public
static
void
checkCode
(
String
code
)
{
if
(
StringUtils
.
isEmpty
(
code
))
{
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_CODE
);
}
}
/**
* 校验state的合法性防止被CSRF
*
* @param newState 新的state,一般为回调时传回的state(可能被篡改)
* @param originalState 原始的state,发起授权时向第三方平台传递的state
*/
public
static
void
checkState
(
String
newState
,
String
originalState
)
{
// 如果原始state为空,表示当前平台未使用state
if
(
StringUtils
.
isEmpty
(
originalState
))
{
return
;
}
// 如果授权之前使用了state,但是回调时未返回state,则表示当前请求为非法的请求,可能正在被CSRF攻击
if
(
StringUtils
.
isEmpty
(
newState
))
{
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_REQUEST
);
}
// 如果授权前后的state不一致,则表示当前请求为非法的请求,新的state可能为伪造
if
(!
newState
.
equals
(
originalState
))
{
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_REQUEST
);
}
}
}
src/main/java/me/zhyd/oauth/utils/AuthState.java
已删除
100644 → 0
浏览文件 @
094c2979
package
me.zhyd.oauth.utils
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.util.RandomUtil
;
import
com.alibaba.fastjson.JSON
;
import
lombok.extern.slf4j.Slf4j
;
import
me.zhyd.oauth.config.AuthSource
;
import
me.zhyd.oauth.exception.AuthException
;
import
me.zhyd.oauth.model.AuthResponseStatus
;
import
java.nio.charset.Charset
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
* state工具,负责创建、获取和删除state
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
*/
@Slf4j
public
class
AuthState
{
/**
* 空字符串
*/
private
static
final
String
EMPTY_STR
=
""
;
/**
* state存储器
*/
private
static
ConcurrentHashMap
<
String
,
String
>
stateBucket
=
new
ConcurrentHashMap
<>();
/**
* 生成随机的state
*
* @param source oauth平台
* @return state
*/
public
static
String
create
(
AuthSource
source
)
{
return
create
(
source
.
name
());
}
/**
* 生成随机的state
*
* @param source oauth平台
* @return state
*/
public
static
String
create
(
String
source
)
{
return
create
(
source
,
RandomUtil
.
randomString
(
4
));
}
/**
* 创建state
*
* @param source oauth平台
* @param body 希望加密到state的消息体
* @return state
*/
public
static
String
create
(
AuthSource
source
,
Object
body
)
{
return
create
(
source
,
JSON
.
toJSONString
(
body
));
}
/**
* 创建state
*
* @param source oauth平台
* @param body 希望加密到state的消息体
* @return state
*/
public
static
String
create
(
String
source
,
Object
body
)
{
return
create
(
source
,
JSON
.
toJSONString
(
body
));
}
/**
* 创建state
*
* @param source oauth平台
* @param body 希望加密到state的消息体
* @return state
*/
public
static
String
create
(
AuthSource
source
,
String
body
)
{
return
create
(
source
.
name
(),
body
);
}
/**
* 创建state
*
* @param source oauth平台
* @param body 希望加密到state的消息体
* @return state
*/
public
static
String
create
(
String
source
,
String
body
)
{
String
currentIp
=
getCurrentIp
();
String
simpleKey
=
((
source
+
currentIp
));
String
key
=
Base64
.
encode
(
simpleKey
.
getBytes
(
Charset
.
forName
(
"UTF-8"
)));
log
.
debug
(
"Create the state: ip={}, platform={}, simpleKey={}, key={}, body={}"
,
currentIp
,
source
,
simpleKey
,
key
,
body
);
if
(
stateBucket
.
containsKey
(
key
))
{
log
.
debug
(
"Get from bucket: {}"
,
stateBucket
.
get
(
key
));
return
stateBucket
.
get
(
key
);
}
String
simpleState
=
source
+
"_"
+
currentIp
+
"_"
+
body
;
String
state
=
Base64
.
encode
(
simpleState
.
getBytes
(
Charset
.
forName
(
"UTF-8"
)));
log
.
debug
(
"Create a new state: {}"
,
state
,
simpleState
);
stateBucket
.
put
(
key
,
state
);
return
state
;
}
/**
* 获取state
*
* @param source oauth平台
* @return state
*/
public
static
String
get
(
AuthSource
source
)
{
return
get
(
source
.
name
());
}
/**
* 获取state
*
* @param source oauth平台
* @return state
*/
public
static
String
get
(
String
source
)
{
String
currentIp
=
getCurrentIp
();
String
simpleKey
=
((
source
+
currentIp
));
String
key
=
Base64
.
encode
(
simpleKey
.
getBytes
(
Charset
.
forName
(
"UTF-8"
)));
log
.
debug
(
"Get state by the key[{}], current ip[{}]"
,
key
,
currentIp
);
return
stateBucket
.
get
(
key
);
}
/**
* 获取state中保存的body内容
*
* @param source oauth平台
* @param state 加密后的state
* @param clazz body的实际类型
* @param <T> 需要转换的具体的class类型
* @return state
*/
public
static
<
T
>
T
getBody
(
AuthSource
source
,
String
state
,
Class
<
T
>
clazz
)
{
return
getBody
(
source
.
name
(),
state
,
clazz
);
}
/**
* 获取state中保存的body内容
*
* @param source oauth平台
* @param state 加密后的state
* @param clazz body的实际类型
* @param <T> 需要转换的具体的class类型
* @return state
*/
public
static
<
T
>
T
getBody
(
String
source
,
String
state
,
Class
<
T
>
clazz
)
{
if
(
StringUtils
.
isEmpty
(
state
)
||
null
==
clazz
)
{
return
null
;
}
log
.
debug
(
"Get body from the state[{}] of the {} and convert it to {}"
,
state
,
source
,
clazz
.
toString
());
String
currentIp
=
getCurrentIp
();
String
decodedState
=
Base64
.
decodeStr
(
state
);
log
.
debug
(
"The decoded state is [{}]"
,
decodedState
);
if
(!
decodedState
.
startsWith
(
source
))
{
return
null
;
}
String
noneSourceState
=
decodedState
.
substring
(
source
.
length
()
+
1
);
if
(!
noneSourceState
.
startsWith
(
currentIp
))
{
// ip不相同,可能为非法的请求
throw
new
AuthException
(
AuthResponseStatus
.
ILLEGAL_REQUEST
);
}
String
body
=
noneSourceState
.
substring
(
currentIp
.
length
()
+
1
);
log
.
debug
(
"body is [{}]"
,
body
);
if
(
clazz
==
String
.
class
)
{
return
(
T
)
body
;
}
if
(
clazz
==
Integer
.
class
)
{
return
(
T
)
Integer
.
valueOf
(
Integer
.
parseInt
(
body
));
}
if
(
clazz
==
Long
.
class
)
{
return
(
T
)
Long
.
valueOf
(
Long
.
parseLong
(
body
));
}
if
(
clazz
==
Short
.
class
)
{
return
(
T
)
Short
.
valueOf
(
Short
.
parseShort
(
body
));
}
if
(
clazz
==
Double
.
class
)
{
return
(
T
)
Double
.
valueOf
(
Double
.
parseDouble
(
body
));
}
if
(
clazz
==
Float
.
class
)
{
return
(
T
)
Float
.
valueOf
(
Float
.
parseFloat
(
body
));
}
if
(
clazz
==
Boolean
.
class
)
{
return
(
T
)
Boolean
.
valueOf
(
Boolean
.
parseBoolean
(
body
));
}
if
(
clazz
==
Byte
.
class
)
{
return
(
T
)
Byte
.
valueOf
(
Byte
.
parseByte
(
body
));
}
return
JSON
.
parseObject
(
body
,
clazz
);
}
/**
* 登录成功后,清除state
*
* @param source oauth平台
*/
public
static
void
delete
(
String
source
)
{
String
currentIp
=
getCurrentIp
();
String
simpleKey
=
((
source
+
currentIp
));
String
key
=
Base64
.
encode
(
simpleKey
.
getBytes
(
Charset
.
forName
(
"UTF-8"
)));
log
.
debug
(
"Delete used state[{}] by the key[{}], current ip[{}]"
,
stateBucket
.
get
(
key
),
key
,
currentIp
);
stateBucket
.
remove
(
key
);
}
/**
* 登录成功后,清除state
*
* @param source oauth平台
*/
public
static
void
delete
(
AuthSource
source
)
{
delete
(
source
.
name
());
}
private
static
String
getCurrentIp
()
{
String
currentIp
=
IpUtils
.
getIp
();
return
StringUtils
.
isEmpty
(
currentIp
)
?
EMPTY_STR
:
currentIp
;
}
}
src/main/java/me/zhyd/oauth/utils/AuthStateUtils.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.utils
;
/**
* AuthState工具类,默认只提供一个创建随机uuid的方法
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.9.3
*/
public
class
AuthStateUtils
{
/**
* 生成随机state,采用{@see https://github.com/lets-mica/mica}的UUID工具
*
* @return 随机的state字符串
*/
public
static
String
createState
()
{
return
UuidUtils
.
getUUID
();
}
}
src/main/java/me/zhyd/oauth/utils/GlobalAuthUtil.java
浏览文件 @
8e99e545
...
...
@@ -21,8 +21,7 @@ import java.util.*;
* 全局的工具类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
GlobalAuthUtil
{
private
static
final
Charset
DEFAULT_ENCODING
=
StandardCharsets
.
UTF_8
;
...
...
src/main/java/me/zhyd/oauth/utils/IpUtils.java
浏览文件 @
8e99e545
...
...
@@ -7,8 +7,7 @@ import java.net.UnknownHostException;
* 获取IP的工具类
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.0
* @since 1.0.0
*/
public
class
IpUtils
{
...
...
@@ -17,7 +16,7 @@ public class IpUtils {
*
* @return ip
*/
public
static
String
getIp
()
{
public
static
String
get
Local
Ip
()
{
try
{
return
InetAddress
.
getLocalHost
().
getHostAddress
();
}
catch
(
UnknownHostException
e
)
{
...
...
@@ -25,4 +24,4 @@ public class IpUtils {
return
null
;
}
}
}
\ No newline at end of file
}
src/main/java/me/zhyd/oauth/utils/StringUtils.java
浏览文件 @
8e99e545
package
me.zhyd.oauth.utils
;
import
java.nio.charset.StandardCharsets
;
import
java.util.concurrent.ThreadLocalRandom
;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @since 1.8
* @since 1.0.0
*/
public
class
StringUtils
{
...
...
@@ -14,4 +16,24 @@ public class StringUtils {
public
static
boolean
isNotEmpty
(
String
str
)
{
return
!
isEmpty
(
str
);
}
/**
* 如果给定字符串{@code str}中不包含{@code appendStr},则在{@code str}后追加{@code appendStr};
* 如果已包含{@code appendStr},则在{@code str}后追加{@code otherwise}
*
* @param str 给定的字符串
* @param appendStr 需要追加的内容
* @param otherwise 当{@code appendStr}不满足时追加到{@code str}后的内容
* @return 追加后的字符串
*/
public
static
String
appendIfNotContain
(
String
str
,
String
appendStr
,
String
otherwise
)
{
if
(
isEmpty
(
str
)
||
isEmpty
(
appendStr
))
{
return
str
;
}
if
(
str
.
contains
(
appendStr
))
{
return
str
.
concat
(
otherwise
);
}
return
str
.
concat
(
appendStr
);
}
}
src/main/java/me/zhyd/oauth/utils/UrlBuilder.java
浏览文件 @
8e99e545
...
...
@@ -14,8 +14,7 @@ import java.util.Map;
* </p>
*
* @author yangkai.shen (https://xkcoding.com)
* @version 1.0
* @since 1.8
* @since 1.9.0
*/
@Setter
public
class
UrlBuilder
{
...
...
@@ -72,7 +71,7 @@ public class UrlBuilder {
if
(
MapUtil
.
isEmpty
(
this
.
params
))
{
return
this
.
baseUrl
;
}
String
baseUrl
=
Str
Util
.
addSuffixIfNot
(
this
.
baseUrl
,
"?
"
);
String
baseUrl
=
Str
ingUtils
.
appendIfNotContain
(
this
.
baseUrl
,
"?"
,
"&
"
);
String
paramString
=
GlobalAuthUtil
.
parseMapToString
(
this
.
params
,
encode
);
return
baseUrl
+
paramString
;
}
...
...
src/main/java/me/zhyd/oauth/utils/UuidUtils.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.utils
;
import
java.nio.charset.StandardCharsets
;
import
java.util.concurrent.ThreadLocalRandom
;
/**
* 高性能的创建UUID的工具类,{@see https://github.com/lets-mica/mica}
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.9.3
*/
public
class
UuidUtils
{
/**
* All possible chars for representing a number as a String
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/NumberUtil.java#L113
*/
private
final
static
byte
[]
DIGITS
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
,
'h'
,
'i'
,
'j'
,
'k'
,
'l'
,
'm'
,
'n'
,
'o'
,
'p'
,
'q'
,
'r'
,
's'
,
't'
,
'u'
,
'v'
,
'w'
,
'x'
,
'y'
,
'z'
,
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
,
'G'
,
'H'
,
'I'
,
'J'
,
'K'
,
'L'
,
'M'
,
'N'
,
'O'
,
'P'
,
'Q'
,
'R'
,
'S'
,
'T'
,
'U'
,
'V'
,
'W'
,
'X'
,
'Y'
,
'Z'
};
/**
* 生成uuid,采用 jdk 9 的形式,优化性能
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L335
* <p>
* 关于mica uuid生成方式的压测结果,可以参考:https://github.com/lets-mica/mica-jmh/wiki/uuid
*
* @return UUID
*/
public
static
String
getUUID
()
{
ThreadLocalRandom
random
=
ThreadLocalRandom
.
current
();
long
lsb
=
random
.
nextLong
();
long
msb
=
random
.
nextLong
();
byte
[]
buf
=
new
byte
[
32
];
formatUnsignedLong
(
lsb
,
buf
,
20
,
12
);
formatUnsignedLong
(
lsb
>>>
48
,
buf
,
16
,
4
);
formatUnsignedLong
(
msb
,
buf
,
12
,
4
);
formatUnsignedLong
(
msb
>>>
16
,
buf
,
8
,
4
);
formatUnsignedLong
(
msb
>>>
32
,
buf
,
0
,
8
);
return
new
String
(
buf
,
StandardCharsets
.
UTF_8
);
}
/**
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L348
*/
private
static
void
formatUnsignedLong
(
long
val
,
byte
[]
buf
,
int
offset
,
int
len
)
{
int
charPos
=
offset
+
len
;
int
radix
=
1
<<
4
;
int
mask
=
radix
-
1
;
do
{
buf
[--
charPos
]
=
DIGITS
[((
int
)
val
)
&
mask
];
val
>>>=
4
;
}
while
(
charPos
>
offset
);
}
}
src/test/java/me/zhyd/oauth/AuthRequestTest.java
浏览文件 @
8e99e545
此差异已折叠。
点击以展开。
src/test/java/me/zhyd/oauth/cache/AuthStateCacheTest.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.cache
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
java.util.concurrent.TimeUnit
;
public
class
AuthStateCacheTest
{
@Test
public
void
cache1
()
throws
InterruptedException
{
AuthStateCache
.
cache
(
"key"
,
"value"
);
Assert
.
assertEquals
(
AuthStateCache
.
get
(
"key"
),
"value"
);
TimeUnit
.
MILLISECONDS
.
sleep
(
4
);
Assert
.
assertEquals
(
AuthStateCache
.
get
(
"key"
),
"value"
);
}
@Test
public
void
cache2
()
throws
InterruptedException
{
AuthStateCache
.
cache
(
"key"
,
"value"
,
10
);
Assert
.
assertEquals
(
AuthStateCache
.
get
(
"key"
),
"value"
);
// 没过期
TimeUnit
.
MILLISECONDS
.
sleep
(
5
);
Assert
.
assertEquals
(
AuthStateCache
.
get
(
"key"
),
"value"
);
// 过期
TimeUnit
.
MILLISECONDS
.
sleep
(
6
);
Assert
.
assertNull
(
AuthStateCache
.
get
(
"key"
));
}
}
src/test/java/me/zhyd/oauth/utils/AuthStateTest.java
已删除
100644 → 0
浏览文件 @
094c2979
package
me.zhyd.oauth.utils
;
import
cn.hutool.core.date.DatePattern
;
import
cn.hutool.core.date.DateUtil
;
import
me.zhyd.oauth.config.AuthConfig
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
java.util.*
;
public
class
AuthStateTest
{
/**
* step1 生成state: 预期创建一个新的state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9yM3ll
*
* step2 重复生成state: 预期从bucket中返回一个可用的state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9yM3ll
*
* step3 获取state: 预期获取上面生成的state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9yM3ll
*
* step4 删除state: 预期删除掉上面创建的state...
*
* step5 重新获取state: 预期返回null...
* null
*/
@Test
public
void
usage
()
{
String
source
=
"github"
;
System
.
out
.
println
(
"\nstep1 生成state: 预期创建一个新的state..."
);
String
state
=
AuthState
.
create
(
source
);
System
.
out
.
println
(
state
);
System
.
out
.
println
(
"\nstep2 重复生成state: 预期从bucket中返回一个可用的state..."
);
String
recreateState
=
AuthState
.
create
(
source
);
System
.
out
.
println
(
recreateState
);
Assert
.
assertEquals
(
state
,
recreateState
);
System
.
out
.
println
(
"\nstep3 获取state: 预期获取上面生成的state..."
);
String
stateByBucket
=
AuthState
.
get
(
source
);
System
.
out
.
println
(
stateByBucket
);
Assert
.
assertEquals
(
state
,
stateByBucket
);
System
.
out
.
println
(
"\nstep4 删除state: 预期删除掉上面创建的state..."
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\nstep5 重新获取state: 预期返回null..."
);
String
deletedState
=
AuthState
.
get
(
source
);
System
.
out
.
println
(
deletedState
);
Assert
.
assertNull
(
deletedState
);
}
/**
* 通过随机字符串生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9wdnAy
*
* 通过传入自定义的字符串生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV/ov5nmmK/kuIDkuKrlrZfnrKbkuLI=
*
* 通过传入数字生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xMTE=
*
* 通过传入日期生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xNTQ2MzE1OTMyMDAw
*
* 通过传入map生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV97InVzZXJUb2tlbiI6Inh4eHh4IiwidXNlcklkIjoxfQ==
*
* 通过传入List生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9bInh4eHgiLCJ4eHh4eHh4eCJd
*
* 通过传入实体类生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV97ImNsaWVudElkIjoieHh4eHgiLCJjbGllbnRTZWNyZXQiOiJ4eHh4eCIsInVuaW9uSWQiOmZhbHNlfQ==
*/
@Test
public
void
create
()
{
String
source
=
"github"
;
System
.
out
.
println
(
"\n通过随机字符串生成state..."
);
String
state
=
AuthState
.
create
(
source
);
System
.
out
.
println
(
state
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入自定义的字符串生成state..."
);
String
stringBody
=
"这是一个字符串"
;
String
stringState
=
AuthState
.
create
(
source
,
stringBody
);
System
.
out
.
println
(
stringState
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入数字生成state..."
);
Integer
numberBody
=
111
;
String
numberState
=
AuthState
.
create
(
source
,
numberBody
);
System
.
out
.
println
(
numberState
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入日期生成state..."
);
Date
dateBody
=
DateUtil
.
parse
(
"2019-01-01 12:12:12"
,
DatePattern
.
NORM_DATETIME_PATTERN
);
String
dateState
=
AuthState
.
create
(
source
,
dateBody
);
System
.
out
.
println
(
dateState
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入map生成state..."
);
Map
<
String
,
Object
>
mapBody
=
new
HashMap
<>();
mapBody
.
put
(
"userId"
,
1
);
mapBody
.
put
(
"userToken"
,
"xxxxx"
);
String
mapState
=
AuthState
.
create
(
source
,
mapBody
);
System
.
out
.
println
(
mapState
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入List生成state..."
);
List
<
String
>
listBody
=
new
ArrayList
<>();
listBody
.
add
(
"xxxx"
);
listBody
.
add
(
"xxxxxxxx"
);
String
listState
=
AuthState
.
create
(
source
,
listBody
);
System
.
out
.
println
(
listState
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入实体类生成state..."
);
AuthConfig
entityBody
=
AuthConfig
.
builder
()
.
clientId
(
"xxxxx"
)
.
clientSecret
(
"xxxxx"
)
.
build
();
String
entityState
=
AuthState
.
create
(
source
,
entityBody
);
System
.
out
.
println
(
entityState
);
AuthState
.
delete
(
source
);
}
/**
* 通过随机字符串生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9kaWNn
* dicg
*
* 通过传入自定义的字符串生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV/ov5nmmK/kuIDkuKrlrZfnrKbkuLI=
* 这是一个字符串
*
* 通过传入数字生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xMTE=
* 111
*
* 通过传入日期生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xNTQ2MzE1OTMyMDAw
* Tue Jan 01 12:12:12 CST 2019
*
* 通过传入map生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV97InVzZXJUb2tlbiI6Inh4eHh4IiwidXNlcklkIjoxfQ==
* {userToken=xxxxx, userId=1}
*
* 通过传入List生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV9bInh4eHgiLCJ4eHh4eHh4eCJd
* [xxxx, xxxxxxxx]
*
* 通过传入实体类生成state...
* Z2l0aHViXzE5Mi4xNjguMTkuMV97ImNsaWVudElkIjoieHh4eHgiLCJjbGllbnRTZWNyZXQiOiJ4eHh4eCIsInVuaW9uSWQiOmZhbHNlfQ==
* me.zhyd.oauth.config.AuthConfig@725bef66
*/
@Test
public
void
getBody
()
{
String
source
=
"github"
;
System
.
out
.
println
(
"\n通过随机字符串生成state..."
);
String
state
=
AuthState
.
create
(
source
);
System
.
out
.
println
(
state
);
String
body
=
AuthState
.
getBody
(
source
,
state
,
String
.
class
);
System
.
out
.
println
(
body
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入自定义的字符串生成state..."
);
String
stringBody
=
"这是一个字符串"
;
String
stringState
=
AuthState
.
create
(
source
,
stringBody
);
System
.
out
.
println
(
stringState
);
stringBody
=
AuthState
.
getBody
(
source
,
stringState
,
String
.
class
);
System
.
out
.
println
(
stringBody
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入数字生成state..."
);
Integer
numberBody
=
111
;
String
numberState
=
AuthState
.
create
(
source
,
numberBody
);
System
.
out
.
println
(
numberState
);
numberBody
=
AuthState
.
getBody
(
source
,
numberState
,
Integer
.
class
);
System
.
out
.
println
(
numberBody
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入日期生成state..."
);
Date
dateBody
=
DateUtil
.
parse
(
"2019-01-01 12:12:12"
,
DatePattern
.
NORM_DATETIME_PATTERN
);
String
dateState
=
AuthState
.
create
(
source
,
dateBody
);
System
.
out
.
println
(
dateState
);
dateBody
=
AuthState
.
getBody
(
source
,
dateState
,
Date
.
class
);
System
.
out
.
println
(
dateBody
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入map生成state..."
);
Map
<
String
,
Object
>
mapBody
=
new
HashMap
<>();
mapBody
.
put
(
"userId"
,
1
);
mapBody
.
put
(
"userToken"
,
"xxxxx"
);
String
mapState
=
AuthState
.
create
(
source
,
mapBody
);
System
.
out
.
println
(
mapState
);
mapBody
=
AuthState
.
getBody
(
source
,
mapState
,
Map
.
class
);
System
.
out
.
println
(
mapBody
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入List生成state..."
);
List
<
String
>
listBody
=
new
ArrayList
<>();
listBody
.
add
(
"xxxx"
);
listBody
.
add
(
"xxxxxxxx"
);
String
listState
=
AuthState
.
create
(
source
,
listBody
);
System
.
out
.
println
(
listState
);
listBody
=
AuthState
.
getBody
(
source
,
listState
,
List
.
class
);
System
.
out
.
println
(
listBody
);
AuthState
.
delete
(
source
);
System
.
out
.
println
(
"\n通过传入实体类生成state..."
);
AuthConfig
entityBody
=
AuthConfig
.
builder
()
.
clientId
(
"xxxxx"
)
.
clientSecret
(
"xxxxx"
)
.
build
();
String
entityState
=
AuthState
.
create
(
source
,
entityBody
);
System
.
out
.
println
(
entityState
);
entityBody
=
AuthState
.
getBody
(
source
,
entityState
,
AuthConfig
.
class
);
System
.
out
.
println
(
entityBody
);
AuthState
.
delete
(
source
);
}
@Test
public
void
getErrorStateBody
()
{
String
source
=
"github"
;
String
state
=
"1111111111111111111111111111111"
;
String
body
=
AuthState
.
getBody
(
source
,
state
,
String
.
class
);
System
.
out
.
println
(
body
);
AuthState
.
delete
(
source
);
}
}
\ No newline at end of file
src/test/java/me/zhyd/oauth/utils/CustomTest.java
浏览文件 @
8e99e545
package
me.zhyd.oauth.utils
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson.JSONPath
;
import
org.junit.Test
;
...
...
@@ -12,11 +11,9 @@ import java.util.List;
import
java.util.Map
;
/**
* 其他测试方法
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @website https://www.zhyd.me
* @date 2019/7/19 15:52
* @since 1.8
*/
public
class
CustomTest
{
...
...
@@ -71,7 +68,7 @@ public class CustomTest {
}
@Test
public
void
jsonpath
(){
public
void
jsonpath
()
{
List
<
Map
<
String
,
Map
<
String
,
Object
>>>
list
=
new
ArrayList
<>();
Map
<
String
,
Map
<
String
,
Object
>>
map
=
new
HashMap
<>();
...
...
src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java
浏览文件 @
8e99e545
...
...
@@ -21,18 +21,43 @@ public class UrlBuilderTest {
.
clientId
(
"appid-110110110"
)
.
clientSecret
(
"secret-110110110"
)
.
redirectUri
(
"https://xkcoding.com"
)
.
state
(
AuthState
.
create
(
AuthSource
.
WECHAT
))
.
build
();
String
build
=
UrlBuilder
.
fromBaseUrl
(
AuthSource
.
WECHAT
.
authorize
())
.
queryParam
(
"appid"
,
config
.
getClientId
())
.
queryParam
(
"redirect_uri"
,
config
.
getRedirectUri
())
.
queryParam
(
"response_type"
,
"code"
)
.
queryParam
(
"scope"
,
"snsapi_login"
)
.
queryParam
(
"state"
,
config
.
getState
().
concat
(
"#wechat_redirect"
)
)
.
queryParam
(
"state"
,
""
)
.
build
(
false
);
System
.
out
.
println
(
build
);
AuthWeChatRequest
request
=
new
AuthWeChatRequest
(
config
);
String
authorize
=
request
.
authorize
();
Assert
.
assertEquals
(
build
,
authorize
);
AuthState
.
delete
(
AuthSource
.
WECHAT
);
String
authorize
=
request
.
authorize
(
"state"
);
System
.
out
.
println
(
authorize
);
}
@Test
public
void
build
()
{
String
url
=
UrlBuilder
.
fromBaseUrl
(
"https://www.zhyd.me"
)
.
queryParam
(
"name"
,
"yadong.zhang"
)
.
build
();
Assert
.
assertEquals
(
url
,
"https://www.zhyd.me?name=yadong.zhang"
);
url
=
UrlBuilder
.
fromBaseUrl
(
url
)
.
queryParam
(
"github"
,
"https://github.com/zhangyd-c"
)
.
build
();
Assert
.
assertEquals
(
url
,
"https://www.zhyd.me?name=yadong.zhang&github=https://github.com/zhangyd-c"
);
}
@Test
public
void
build1
()
{
String
url
=
UrlBuilder
.
fromBaseUrl
(
"https://www.zhyd.me"
)
.
queryParam
(
"name"
,
"yadong.zhang"
)
.
build
(
true
);
Assert
.
assertEquals
(
url
,
"https://www.zhyd.me?name=yadong.zhang"
);
url
=
UrlBuilder
.
fromBaseUrl
(
url
)
.
queryParam
(
"github"
,
"https://github.com/zhangyd-c"
)
.
build
(
true
);
Assert
.
assertEquals
(
url
,
"https://www.zhyd.me?name=yadong.zhang&github=https%3A%2F%2Fgithub.com%2Fzhangyd-c"
);
}
}
src/test/java/me/zhyd/oauth/utils/UuidUtilsTest.java
0 → 100644
浏览文件 @
8e99e545
package
me.zhyd.oauth.utils
;
import
org.junit.Test
;
public
class
UuidUtilsTest
{
@Test
public
void
getUUID
()
{
String
uuid
=
UuidUtils
.
getUUID
();
System
.
out
.
println
(
uuid
);
}
}
update.md
浏览文件 @
8e99e545
### 2019/07/30 ([v1.9.3](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.3))
1.
规范注释
2.
增加State缓存,
`AuthCallback`
中增加默认的校验state的方法
3.
增加默认的state生成方法,参考
`AuthStateUtils.java`
和
`UuidUtils.java`
4.
升级
`hutool-http`
版本到
`v4.6.0`
5.
修复其他一些问题
### 2019/07/27
1.
`IpUtils.getIp`
改名为
`IpUtils.getLocalIp`
2.
规范注释
### 2019/07/25
1.
`AuthConfig`
类中去掉state参数
2.
删除
`AuthState`
类
3.
增加
`authorize(String)`
方法,并且使用
`@Deprecated`
标记
`authorize()`
方法
### 2019/07/22 ([v1.9.2](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.2))
1.
合并github上
[
xkcoding
](
https://github.com/xkcoding
)
的
[
pr#26
](
https://github.com/zhangyd-c/JustAuth/pull/26
)
,AuthConfig类添加lombok注解,方便
[
justauth-spring-boot-starter
](
https://github.com/xkcoding/justauth-spring-boot-starter
)
直接使用
...
...
@@ -34,7 +53,7 @@
2.
将CSDN相关的类置为
`Deprecated`
,后续可能会删除,也可能一直保留。毕竟CSDN的openAPI已经不对外开放了。
3.
`BaseAuthRequest`
改名为
`AuthDefaultRequest`
4.
`ResponseStatus`
改名为
`AuthResponseStatus`
并且移动到
`me.zhyd.oauth.model`
5.
合并github上
[
@xkcoding
](
https://github.com/xkcoding
)
的
[
pr#18
](
https://github.com/zhangyd-c/JustAuth/pull/18
)
,修复小米回调错误问题 同时 支持微信获取
5.
合并github上
[
@xkcoding
](
https://github.com/xkcoding
)
的
[
pr#18
](
https://github.com/zhangyd-c/JustAuth/pull/18
)
,修复小米回调错误问题 同时 支持微信获取
unionId
### 2019/07/15 ([v1.8.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.8.1))
1.
新增
`AuthState`
类,内置默认的state生成规则和校验规则
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录