mirror of
https://gitee.com/yadong.zhang/JustAuth.git
synced 2025-12-06 16:58:24 +08:00
Merge branch 'dev'
This commit is contained in:
commit
8e99e54519
17
README.md
17
README.md
@ -6,7 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
<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>
|
||||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
<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>
|
<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>
|
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||||
</a>
|
</a>
|
||||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/">
|
<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>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>me.zhyd.oauth</groupId>
|
<groupId>me.zhyd.oauth</groupId>
|
||||||
<artifactId>JustAuth</artifactId>
|
<artifactId>JustAuth</artifactId>
|
||||||
<version>1.9.2</version>
|
<version>1.9.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
- 调用api
|
- 调用api
|
||||||
@ -91,14 +91,19 @@ AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
|||||||
// 生成授权页面
|
// 生成授权页面
|
||||||
authRequest.authorize();
|
authRequest.authorize();
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数
|
// 授权登录后会返回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);
|
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**:
|
**配套Demo**:
|
||||||
- [Springboot版](https://gitee.com/yadong.zhang/JustAuth-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**:
|
**配套SpringBoot starter**:
|
||||||
|
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@ -54,7 +54,7 @@
|
|||||||
<maven-source.version>2.2.1</maven-source.version>
|
<maven-source.version>2.2.1</maven-source.version>
|
||||||
<maven-compiler.version>3.7.0</maven-compiler.version>
|
<maven-compiler.version>3.7.0</maven-compiler.version>
|
||||||
<maven.test.skip>true</maven.test.skip>
|
<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>
|
<lombok-version>1.18.4</lombok-version>
|
||||||
<junit-version>4.11</junit-version>
|
<junit-version>4.11</junit-version>
|
||||||
<fastjson-version>1.2.58</fastjson-version>
|
<fastjson-version>1.2.58</fastjson-version>
|
||||||
|
|||||||
50
src/main/java/me/zhyd/oauth/cache/AuthCache.java
vendored
Normal file
50
src/main/java/me/zhyd/oauth/cache/AuthCache.java
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
src/main/java/me/zhyd/oauth/cache/AuthCacheScheduler.java
vendored
Normal file
39
src/main/java/me/zhyd/oauth/cache/AuthCacheScheduler.java
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
144
src/main/java/me/zhyd/oauth/cache/AuthDefaultCache.java
vendored
Normal file
144
src/main/java/me/zhyd/oauth/cache/AuthDefaultCache.java
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/main/java/me/zhyd/oauth/cache/AuthStateCache.java
vendored
Normal file
51
src/main/java/me/zhyd/oauth/cache/AuthStateCache.java
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,6 @@ import lombok.*;
|
|||||||
* JustAuth配置类
|
* JustAuth配置类
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@ -45,13 +44,6 @@ public class AuthConfig {
|
|||||||
*/
|
*/
|
||||||
private boolean unionId;
|
private boolean unionId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 一个神奇的参数,最好使用随机的不可测的内容,可以用来防止CSRF攻击
|
|
||||||
* <p>
|
|
||||||
* 1.8.0版本新增参数
|
|
||||||
*/
|
|
||||||
private String state;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stack Overflow Key
|
* Stack Overflow Key
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import me.zhyd.oauth.model.AuthResponseStatus;
|
|||||||
* 各api需要的url, 用枚举类分平台类型管理
|
* 各api需要的url, 用枚举类分平台类型管理
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public enum AuthSource {
|
public enum AuthSource {
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import lombok.Getter;
|
|||||||
* 今日头条授权登录时的异常状态码
|
* 今日头条授权登录时的异常状态码
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import java.util.Arrays;
|
|||||||
* 用户性别
|
* 用户性别
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import me.zhyd.oauth.model.AuthResponseStatus;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthException extends RuntimeException {
|
public class AuthException extends RuntimeException {
|
||||||
|
|||||||
@ -2,13 +2,13 @@ package me.zhyd.oauth.model;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import me.zhyd.oauth.cache.AuthStateCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权回调时的参数类
|
* 授权回调时的参数类
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.8.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -28,4 +28,14 @@ public class AuthCallback {
|
|||||||
* 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击
|
* 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击
|
||||||
*/
|
*/
|
||||||
private String state;
|
private String state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置的检验state合法性的方法
|
||||||
|
*
|
||||||
|
* @return true: state正常;false:state不正常,可能授权时间过长导致state失效
|
||||||
|
* @since 1.9.3
|
||||||
|
*/
|
||||||
|
public boolean checkState() {
|
||||||
|
return AuthStateCache.containsKey(this.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import lombok.Setter;
|
|||||||
* JustAuth统一授权响应类
|
* JustAuth统一授权响应类
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import lombok.Getter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import lombok.Setter;
|
|||||||
* 授权所需的token
|
* 授权所需的token
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import me.zhyd.oauth.enums.AuthUserGender;
|
|||||||
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
|
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@ -19,6 +18,8 @@ import me.zhyd.oauth.enums.AuthUserGender;
|
|||||||
public class AuthUser {
|
public class AuthUser {
|
||||||
/**
|
/**
|
||||||
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
|
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
|
||||||
|
*
|
||||||
|
* @since 1.3.3
|
||||||
*/
|
*/
|
||||||
private String uuid;
|
private String uuid;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -21,8 +21,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 支付宝登录
|
* 支付宝登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.1
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthAlipayRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("app_id", config.getClientId())
|
.queryParam("app_id", config.getClientId())
|
||||||
.queryParam("scope", "auth_user")
|
.queryParam("scope", "auth_user")
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 百度账号登录
|
* 百度账号登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthBaiduRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("display", "popup")
|
.queryParam("display", "popup")
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,19 +4,18 @@ import cn.hutool.http.HttpResponse;
|
|||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
import me.zhyd.oauth.config.AuthSource;
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.enums.AuthUserGender;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthCallback;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.enums.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cooding登录
|
* Cooding登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthCodingRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("scope", "user")
|
.queryParam("scope", "user")
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,7 @@ import me.zhyd.oauth.model.AuthUser;
|
|||||||
* CSDN登录
|
* CSDN登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class AuthCsdnRequest extends AuthDefaultRequest {
|
public class AuthCsdnRequest extends AuthDefaultRequest {
|
||||||
|
|||||||
@ -2,8 +2,8 @@ package me.zhyd.oauth.request;
|
|||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpRequest;
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.zhyd.oauth.cache.AuthStateCache;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
import me.zhyd.oauth.config.AuthSource;
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
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.AuthChecker;
|
||||||
import me.zhyd.oauth.utils.StringUtils;
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
import me.zhyd.oauth.utils.UuidUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认的request处理类
|
* 默认的request处理类
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class AuthDefaultRequest implements AuthRequest {
|
public abstract class AuthDefaultRequest implements AuthRequest {
|
||||||
@ -43,7 +43,6 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
|||||||
public AuthResponse login(AuthCallback authCallback) {
|
public AuthResponse login(AuthCallback authCallback) {
|
||||||
try {
|
try {
|
||||||
AuthChecker.checkCode(source == AuthSource.ALIPAY ? authCallback.getAuth_code() : authCallback.getCode());
|
AuthChecker.checkCode(source == AuthSource.ALIPAY ? authCallback.getAuth_code() : authCallback.getCode());
|
||||||
AuthChecker.checkState(authCallback.getState(), config.getState());
|
|
||||||
|
|
||||||
AuthToken authToken = this.getAccessToken(authCallback);
|
AuthToken authToken = this.getAccessToken(authCallback);
|
||||||
AuthUser user = this.getUserInfo(authToken);
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @see AuthDefaultRequest#authorize(String)
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
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())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,13 +146,18 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取state,如果为空, 则默认去当前日期的时间戳
|
* 获取state,如果为空, 则默认取当前日期的时间戳
|
||||||
*
|
*
|
||||||
* @param state 原始的state
|
* @param state 原始的state
|
||||||
* @return 返回不为null的state
|
* @return 返回不为null的state
|
||||||
*/
|
*/
|
||||||
protected String getRealState(String 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封装
|
* @param authToken token封装
|
||||||
* @return HttpResponse
|
* @return HttpResponse
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected HttpResponse doPostUserInfo(AuthToken authToken) {
|
protected HttpResponse doPostUserInfo(AuthToken authToken) {
|
||||||
return HttpRequest.post(userInfoUrl(authToken)).execute();
|
return HttpRequest.post(userInfoUrl(authToken)).execute();
|
||||||
}
|
}
|
||||||
@ -184,7 +206,9 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
|||||||
*
|
*
|
||||||
* @param authToken token封装
|
* @param authToken token封装
|
||||||
* @return HttpResponse
|
* @return HttpResponse
|
||||||
|
* @since
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected HttpResponse doPostRevoke(AuthToken authToken) {
|
protected HttpResponse doPostRevoke(AuthToken authToken) {
|
||||||
return HttpRequest.post(revokeUrl(authToken)).execute();
|
return HttpRequest.post(revokeUrl(authToken)).execute();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 钉钉登录
|
* 钉钉登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthDingTalkRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("appid", config.getClientId())
|
.queryParam("appid", config.getClientId())
|
||||||
.queryParam("scope", "snsapi_login")
|
.queryParam("scope", "snsapi_login")
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 抖音登录
|
* 抖音登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.4.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthDouyinRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_key", config.getClientId())
|
.queryParam("client_key", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("scope", "user_info")
|
.queryParam("scope", "user_info")
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* Facebook登录
|
* Facebook登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.3.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthFacebookRequest extends AuthDefaultRequest {
|
public class AuthFacebookRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,7 @@ import me.zhyd.oauth.model.AuthUser;
|
|||||||
* Gitee登录
|
* Gitee登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthGiteeRequest extends AuthDefaultRequest {
|
public class AuthGiteeRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
|||||||
@ -17,8 +17,7 @@ import java.util.Map;
|
|||||||
* Github登录
|
* Github登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthGithubRequest extends AuthDefaultRequest {
|
public class AuthGithubRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
@ -63,12 +62,4 @@ public class AuthGithubRequest extends AuthDefaultRequest {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查响应内容是否正确
|
|
||||||
*
|
|
||||||
* @param object 请求响应内容
|
|
||||||
*/
|
|
||||||
private void checkResponse(JSONObject object) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* Google登录
|
* Google登录
|
||||||
*
|
*
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.3
|
* @since 1.3.0
|
||||||
* @since 1.3
|
|
||||||
*/
|
*/
|
||||||
public class AuthGoogleRequest extends AuthDefaultRequest {
|
public class AuthGoogleRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
@ -61,19 +60,20 @@ public class AuthGoogleRequest extends AuthDefaultRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回认证url,可自行跳转页面
|
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||||
* https://openidconnect.googleapis.com/v1/userinfo
|
|
||||||
*
|
*
|
||||||
|
* @param state state 验证授权流程的参数,可以防止csrf
|
||||||
* @return 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("scope", "openid%20email%20profile")
|
.queryParam("scope", "openid%20email%20profile")
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 领英登录
|
* 领英登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.4.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthLinkedinRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("scope", "r_liteprofile%20r_emailaddress%20w_member_social")
|
.queryParam("scope", "r_liteprofile%20r_emailaddress%20w_member_social")
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,7 @@ import java.text.MessageFormat;
|
|||||||
* 小米登录
|
* 小米登录
|
||||||
*
|
*
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.5
|
* @since 1.5.0
|
||||||
* @since 1.5
|
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AuthMiRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("scope", "user/profile%20user/openIdV2%20user/phoneAndEmail")
|
.queryParam("scope", "user/profile%20user/openIdV2%20user/phoneAndEmail")
|
||||||
.queryParam("skip_confirm", "false")
|
.queryParam("skip_confirm", "false")
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,7 @@ import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
|
|||||||
* 微软登录
|
* 微软登录
|
||||||
*
|
*
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.5
|
* @since 1.5.0
|
||||||
* @since 1.5
|
|
||||||
*/
|
*/
|
||||||
public class AuthMicrosoftRequest extends AuthDefaultRequest {
|
public class AuthMicrosoftRequest extends AuthDefaultRequest {
|
||||||
public AuthMicrosoftRequest(AuthConfig config) {
|
public AuthMicrosoftRequest(AuthConfig config) {
|
||||||
@ -102,19 +101,21 @@ public class AuthMicrosoftRequest extends AuthDefaultRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回认证url,可自行跳转页面
|
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||||
*
|
*
|
||||||
|
* @param state state 验证授权流程的参数,可以防止csrf
|
||||||
* @return 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("response_mode", "query")
|
.queryParam("response_mode", "query")
|
||||||
.queryParam("scope", "offline_access%20user.read%20mail.read")
|
.queryParam("scope", "offline_access%20user.read%20mail.read")
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* oschina登录
|
* oschina登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthOschinaRequest extends AuthDefaultRequest {
|
public class AuthOschinaRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ public class AuthOschinaRequest extends AuthDefaultRequest {
|
|||||||
/**
|
/**
|
||||||
* 返回获取accessToken的url
|
* 返回获取accessToken的url
|
||||||
*
|
*
|
||||||
* @param code
|
* @param code 授权回调时带回的授权码
|
||||||
* @return 返回获取accessToken的url
|
* @return 返回获取accessToken的url
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -19,8 +19,7 @@ import static me.zhyd.oauth.config.AuthSource.PINTEREST;
|
|||||||
* Pinterest登录
|
* Pinterest登录
|
||||||
*
|
*
|
||||||
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||||
* @version 1.9.0
|
* @since 1.9.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthPinterestRequest extends AuthDefaultRequest {
|
public class AuthPinterestRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
@ -69,14 +68,21 @@ public class AuthPinterestRequest extends AuthDefaultRequest {
|
|||||||
return jsonObject.getJSONObject("60x60").getString("url");
|
return jsonObject.getJSONObject("60x60").getString("url");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||||
|
*
|
||||||
|
* @param state state 验证授权流程的参数,可以防止csrf
|
||||||
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("scope", "read_public")
|
.queryParam("scope", "read_public")
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,8 +20,7 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.0
|
* @since 1.1.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthQqRequest extends AuthDefaultRequest {
|
public class AuthQqRequest extends AuthDefaultRequest {
|
||||||
public AuthQqRequest(AuthConfig config) {
|
public AuthQqRequest(AuthConfig config) {
|
||||||
@ -69,6 +68,13 @@ public class AuthQqRequest extends AuthDefaultRequest {
|
|||||||
.build();
|
.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) {
|
private String getOpenId(AuthToken authToken) {
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.fromBaseUrl("https://graph.qq.com/oauth2.0/me")
|
HttpResponse response = HttpRequest.get(UrlBuilder.fromBaseUrl("https://graph.qq.com/oauth2.0/me")
|
||||||
.queryParam("access_token", authToken.getAccessToken())
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
|||||||
@ -19,8 +19,7 @@ import static me.zhyd.oauth.model.AuthResponseStatus.SUCCESS;
|
|||||||
* 人人登录
|
* 人人登录
|
||||||
*
|
*
|
||||||
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||||
* @version 1.9.0
|
* @since 1.9.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthRenrenRequest extends AuthDefaultRequest {
|
public class AuthRenrenRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
|||||||
@ -8,20 +8,33 @@ import me.zhyd.oauth.model.AuthToken;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public interface AuthRequest {
|
public interface AuthRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回认证url,可自行跳转页面
|
* 返回授权url,可自行跳转页面
|
||||||
|
* <p>
|
||||||
|
* 不建议使用该方式获取授权地址,不带{@code state}的授权地址,容易受到csrf攻击。
|
||||||
|
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址,在回调方法中对{@code state}进行校验
|
||||||
*
|
*
|
||||||
* @return 返回授权地址
|
* @return 返回授权地址
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
default String authorize() {
|
default String authorize() {
|
||||||
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第三方登录
|
* 第三方登录
|
||||||
*
|
*
|
||||||
|
|||||||
@ -18,8 +18,7 @@ import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
|
|||||||
* Stack Overflow登录
|
* Stack Overflow登录
|
||||||
*
|
*
|
||||||
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||||
* @version 1.9.0
|
* @since 1.9.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
@ -67,14 +66,21 @@ public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||||
|
*
|
||||||
|
* @param state state 验证授权流程的参数,可以防止csrf
|
||||||
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("scope", "read_inbox")
|
.queryParam("scope", "read_inbox")
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,11 @@ import cn.hutool.http.HttpResponse;
|
|||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
import me.zhyd.oauth.config.AuthSource;
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.enums.AuthUserGender;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthCallback;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.enums.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
@ -16,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 淘宝登录
|
* 淘宝登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.1.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthTaobaoRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("view", "web")
|
.queryParam("view", "web")
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,7 @@ import me.zhyd.oauth.model.*;
|
|||||||
* Teambition授权登录
|
* Teambition授权登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.9.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthTeambitionRequest extends AuthDefaultRequest {
|
public class AuthTeambitionRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 腾讯云登录
|
* 腾讯云登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthTencentCloudRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_id", config.getClientId())
|
.queryParam("client_id", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("scope", "user")
|
.queryParam("scope", "user")
|
||||||
.queryParam("state", getRealState(config.getState()))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 今日头条登录
|
* 今日头条登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.5
|
* @since 1.6.0-beta
|
||||||
* @since 1.5
|
|
||||||
*/
|
*/
|
||||||
public class AuthToutiaoRequest extends AuthDefaultRequest {
|
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 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("client_key", config.getClientId())
|
.queryParam("client_key", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("state", getRealState(config.getState()))
|
|
||||||
.queryParam("auth_only", 1)
|
.queryParam("auth_only", 1)
|
||||||
.queryParam("display", 0)
|
.queryParam("display", 0)
|
||||||
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 微信登录
|
* 微信登录
|
||||||
*
|
*
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.0
|
* @since 1.1.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthWeChatRequest extends AuthDefaultRequest {
|
public class AuthWeChatRequest extends AuthDefaultRequest {
|
||||||
public AuthWeChatRequest(AuthConfig config) {
|
public AuthWeChatRequest(AuthConfig config) {
|
||||||
@ -100,18 +99,20 @@ public class AuthWeChatRequest extends AuthDefaultRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回认证url,可自行跳转页面
|
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||||
*
|
*
|
||||||
|
* @param state state 验证授权流程的参数,可以防止csrf
|
||||||
* @return 返回授权地址
|
* @return 返回授权地址
|
||||||
|
* @since 1.9.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("appid", config.getClientId())
|
.queryParam("appid", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("scope", "snsapi_login")
|
.queryParam("scope", "snsapi_login")
|
||||||
.queryParam("state", getRealState(config.getState()).concat("#wechat_redirect"))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,8 +19,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* 微博登录
|
* 微博登录
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthWeiboRequest extends AuthDefaultRequest {
|
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);
|
String oauthParam = String.format("uid=%s&access_token=%s", uid, accessToken);
|
||||||
HttpResponse response = HttpRequest.get(userInfoUrl(authToken))
|
HttpResponse response = HttpRequest.get(userInfoUrl(authToken))
|
||||||
.header("Authorization", "OAuth2 " + oauthParam)
|
.header("Authorization", "OAuth2 " + oauthParam)
|
||||||
.header("API-RemoteIP", IpUtils.getIp())
|
.header("API-RemoteIP", IpUtils.getLocalIp())
|
||||||
.execute();
|
.execute();
|
||||||
String userInfo = response.body();
|
String userInfo = response.body();
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
|
|||||||
@ -9,8 +9,7 @@ import me.zhyd.oauth.model.AuthResponseStatus;
|
|||||||
* 授权配置类的校验器
|
* 授权配置类的校验器
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.6.1-beta
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthChecker {
|
public class AuthChecker {
|
||||||
|
|
||||||
@ -20,6 +19,7 @@ public class AuthChecker {
|
|||||||
* @param config config
|
* @param config config
|
||||||
* @param source source
|
* @param source source
|
||||||
* @return true or false
|
* @return true or false
|
||||||
|
* @since 1.6.1-beta
|
||||||
*/
|
*/
|
||||||
public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
|
public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
|
||||||
boolean isSupported = StringUtils.isNotEmpty(config.getClientId()) && StringUtils.isNotEmpty(config.getClientSecret()) && StringUtils.isNotEmpty(config.getRedirectUri());
|
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 config config
|
||||||
* @param source source
|
* @param source source
|
||||||
|
* @since 1.6.1-beta
|
||||||
*/
|
*/
|
||||||
public static void checkConfig(AuthConfig config, AuthSource source) {
|
public static void checkConfig(AuthConfig config, AuthSource source) {
|
||||||
String redirectUri = config.getRedirectUri();
|
String redirectUri = config.getRedirectUri();
|
||||||
@ -57,31 +58,11 @@ public class AuthChecker {
|
|||||||
* 校验回调传回的code
|
* 校验回调传回的code
|
||||||
*
|
*
|
||||||
* @param code 回调时传回的code
|
* @param code 回调时传回的code
|
||||||
|
* @since 1.8.0
|
||||||
*/
|
*/
|
||||||
public static void checkCode(String code) {
|
public static void checkCode(String code) {
|
||||||
if (StringUtils.isEmpty(code)) {
|
if (StringUtils.isEmpty(code)) {
|
||||||
throw new AuthException(AuthResponseStatus.ILLEGAL_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,230 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
src/main/java/me/zhyd/oauth/utils/AuthStateUtils.java
Normal file
19
src/main/java/me/zhyd/oauth/utils/AuthStateUtils.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,8 +21,7 @@ import java.util.*;
|
|||||||
* 全局的工具类
|
* 全局的工具类
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class GlobalAuthUtil {
|
public class GlobalAuthUtil {
|
||||||
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
|
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
|
||||||
|
|||||||
@ -7,8 +7,7 @@ import java.net.UnknownHostException;
|
|||||||
* 获取IP的工具类
|
* 获取IP的工具类
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.0
|
|
||||||
*/
|
*/
|
||||||
public class IpUtils {
|
public class IpUtils {
|
||||||
|
|
||||||
@ -17,7 +16,7 @@ public class IpUtils {
|
|||||||
*
|
*
|
||||||
* @return ip
|
* @return ip
|
||||||
*/
|
*/
|
||||||
public static String getIp() {
|
public static String getLocalIp() {
|
||||||
try {
|
try {
|
||||||
return InetAddress.getLocalHost().getHostAddress();
|
return InetAddress.getLocalHost().getHostAddress();
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package me.zhyd.oauth.utils;
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @since 1.0.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|
||||||
@ -14,4 +16,24 @@ public class StringUtils {
|
|||||||
public static boolean isNotEmpty(String str) {
|
public static boolean isNotEmpty(String str) {
|
||||||
return !isEmpty(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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,7 @@ import java.util.Map;
|
|||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.0
|
* @since 1.9.0
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
@Setter
|
@Setter
|
||||||
public class UrlBuilder {
|
public class UrlBuilder {
|
||||||
@ -72,7 +71,7 @@ public class UrlBuilder {
|
|||||||
if (MapUtil.isEmpty(this.params)) {
|
if (MapUtil.isEmpty(this.params)) {
|
||||||
return this.baseUrl;
|
return this.baseUrl;
|
||||||
}
|
}
|
||||||
String baseUrl = StrUtil.addSuffixIfNot(this.baseUrl, "?");
|
String baseUrl = StringUtils.appendIfNotContain(this.baseUrl, "?", "&");
|
||||||
String paramString = GlobalAuthUtil.parseMapToString(this.params, encode);
|
String paramString = GlobalAuthUtil.parseMapToString(this.params, encode);
|
||||||
return baseUrl + paramString;
|
return baseUrl + paramString;
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/main/java/me/zhyd/oauth/utils/UuidUtils.java
Normal file
65
src/main/java/me/zhyd/oauth/utils/UuidUtils.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,8 +8,6 @@ import org.junit.Test;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
*/
|
||||||
public class AuthRequestTest {
|
public class AuthRequestTest {
|
||||||
|
|
||||||
@ -19,11 +17,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,11 +32,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +49,10 @@ public class AuthRequestTest {
|
|||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,11 +62,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,11 +77,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,11 +92,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,11 +107,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,11 +122,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
authRequest.login(new AuthCallback());
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +138,12 @@ public class AuthRequestTest {
|
|||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.alipayPublicKey("publicKey")
|
.alipayPublicKey("publicKey")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,11 +153,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,11 +168,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,11 +183,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,11 +198,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,11 +213,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,11 +228,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,11 +243,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,11 +258,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,11 +273,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,11 +288,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.state("state")
|
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行跳转
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
authRequest.authorize("state");
|
||||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
// 1.9.3版本后 如果需要验证state,可以在login之前调用{@see AuthCallback#checkState}方法校验state合法性
|
||||||
|
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||||
AuthResponse login = authRequest.login(new AuthCallback());
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/test/java/me/zhyd/oauth/cache/AuthStateCacheTest.java
vendored
Normal file
32
src/test/java/me/zhyd/oauth/cache/AuthStateCacheTest.java
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,231 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package me.zhyd.oauth.utils;
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.JSONPath;
|
import com.alibaba.fastjson.JSONPath;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -12,11 +11,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 其他测试方法
|
||||||
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @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 {
|
public class CustomTest {
|
||||||
|
|
||||||
|
|||||||
@ -21,18 +21,43 @@ public class UrlBuilderTest {
|
|||||||
.clientId("appid-110110110")
|
.clientId("appid-110110110")
|
||||||
.clientSecret("secret-110110110")
|
.clientSecret("secret-110110110")
|
||||||
.redirectUri("https://xkcoding.com")
|
.redirectUri("https://xkcoding.com")
|
||||||
.state(AuthState.create(AuthSource.WECHAT))
|
|
||||||
.build();
|
.build();
|
||||||
String build = UrlBuilder.fromBaseUrl(AuthSource.WECHAT.authorize())
|
String build = UrlBuilder.fromBaseUrl(AuthSource.WECHAT.authorize())
|
||||||
.queryParam("appid", config.getClientId())
|
.queryParam("appid", config.getClientId())
|
||||||
.queryParam("redirect_uri", config.getRedirectUri())
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.queryParam("response_type", "code")
|
.queryParam("response_type", "code")
|
||||||
.queryParam("scope", "snsapi_login")
|
.queryParam("scope", "snsapi_login")
|
||||||
.queryParam("state", config.getState().concat("#wechat_redirect"))
|
.queryParam("state", "")
|
||||||
.build(false);
|
.build(false);
|
||||||
|
System.out.println(build);
|
||||||
AuthWeChatRequest request = new AuthWeChatRequest(config);
|
AuthWeChatRequest request = new AuthWeChatRequest(config);
|
||||||
String authorize = request.authorize();
|
String authorize = request.authorize("state");
|
||||||
Assert.assertEquals(build, authorize);
|
System.out.println(authorize);
|
||||||
AuthState.delete(AuthSource.WECHAT);
|
}
|
||||||
|
|
||||||
|
@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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/test/java/me/zhyd/oauth/utils/UuidUtilsTest.java
Normal file
13
src/test/java/me/zhyd/oauth/utils/UuidUtilsTest.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class UuidUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getUUID() {
|
||||||
|
|
||||||
|
String uuid = UuidUtils.getUUID();
|
||||||
|
System.out.println(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
update.md
21
update.md
@ -1,3 +1,22 @@
|
|||||||
|
### 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))
|
### 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) 直接使用
|
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已经不对外开放了。
|
2. 将CSDN相关的类置为`Deprecated`,后续可能会删除,也可能一直保留。毕竟CSDN的openAPI已经不对外开放了。
|
||||||
3. `BaseAuthRequest` 改名为 `AuthDefaultRequest`
|
3. `BaseAuthRequest` 改名为 `AuthDefaultRequest`
|
||||||
4. `ResponseStatus` 改名为 `AuthResponseStatus` 并且移动到 `me.zhyd.oauth.model`
|
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))
|
### 2019/07/15 ([v1.8.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.8.1))
|
||||||
1. 新增 `AuthState` 类,内置默认的state生成规则和校验规则
|
1. 新增 `AuthState` 类,内置默认的state生成规则和校验规则
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user