mirror of
https://gitee.com/yadong.zhang/JustAuth.git
synced 2026-01-07 19:31:48 +08:00
✨ 新增AuthState类,内置默认的state生成规则和校验规则
This commit is contained in:
parent
bfe2122962
commit
44bb03d63f
@ -6,7 +6,7 @@
|
||||
</p>
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
||||
<img src="https://img.shields.io/badge/Maven Central-1.8.0-blue.svg" ></img>
|
||||
<img src="https://img.shields.io/badge/Maven Central-1.8.1-blue.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
|
||||
@ -15,7 +15,7 @@
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/">
|
||||
<img src="https://img.shields.io/badge/Docs-1.8.0-orange.svg" ></img>
|
||||
<img src="https://img.shields.io/badge/Docs-1.8.1-orange.svg" ></img>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -68,7 +68,7 @@ JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.8.1</version>
|
||||
</dependency>
|
||||
```
|
||||
- 调用api
|
||||
|
||||
8
pom.xml
8
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.8.1</version>
|
||||
|
||||
<name>JustAuth</name>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||
@ -54,6 +54,7 @@
|
||||
<junit-version>4.11</junit-version>
|
||||
<fastjson-version>1.2.44</fastjson-version>
|
||||
<alipay-sdk-version>3.7.4.ALL</alipay-sdk-version>
|
||||
<slf4j-version>1.7.25</slf4j-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -84,6 +85,11 @@
|
||||
<version>${alipay-sdk-version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
165
src/main/java/me/zhyd/oauth/utils/AuthState.java
Normal file
165
src/main/java/me/zhyd/oauth/utils/AuthState.java
Normal file
@ -0,0 +1,165 @@
|
||||
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.exception.AuthException;
|
||||
import me.zhyd.oauth.request.ResponseStatus;
|
||||
|
||||
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(String source) {
|
||||
return create(source, RandomUtil.randomString(4));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建state
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @param body 希望加密到state的消息体
|
||||
* @return state
|
||||
*/
|
||||
public static String create(String source, Object body) {
|
||||
return create(source, JSON.toJSONString(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建state
|
||||
* state建议格式请参考:https://gitee.com/yadong.zhang/JustAuth/wikis/Q&A?sort_id=1513074#3-%E5%8D%87%E7%BA%A7%E5%88%B0180%E5%90%8E%E5%AF%B9%E4%BA%8Estate%E5%8F%82%E6%95%B0%E6%9C%89%E4%BB%80%E4%B9%88%E7%89%B9%E6%AE%8A%E8%A6%81%E6%B1%82%E5%90%97
|
||||
*
|
||||
* @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(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的实际类型
|
||||
* @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(ResponseStatus.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);
|
||||
}
|
||||
|
||||
private static String getCurrentIp() {
|
||||
String currentIp = IpUtils.getIp();
|
||||
return StringUtils.isEmpty(currentIp) ? EMPTY_STR : currentIp;
|
||||
}
|
||||
}
|
||||
231
src/test/java/me/zhyd/oauth/utils/AuthStateTest.java
Normal file
231
src/test/java/me/zhyd/oauth/utils/AuthStateTest.java
Normal file
@ -0,0 +1,231 @@
|
||||
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 test() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user