mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-06-28 13:34:18 +08:00
增加 state 值校验
This commit is contained in:
parent
d3b337a6a6
commit
e0a609b128
@ -4,7 +4,7 @@ server:
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称 (同时也是 Cookie 名称)
|
||||
token-name: sa-token-oauth2-server
|
||||
token-name: satoken
|
||||
# 是否打印操作日志
|
||||
is-log: true
|
||||
# jwt 秘钥
|
||||
|
@ -30,8 +30,6 @@ OAuth2 集成常见问题整理
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 问:Sa-Token-OAuth2 怎么集成多账号模式?
|
||||
|
||||
在 `configOAuth2Server` 里指定 oauth2 模块使用的 `StpLogic` 对象即可:
|
||||
@ -45,4 +43,17 @@ public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
|
||||
// 指定 oauth2 模块使用的 `StpLogic` 对象
|
||||
SaOAuth2Manager.setStpLogic(StpUserUtil.stpLogic);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### 问:授权码流程中 state 参数是干吗用的?
|
||||
|
||||
state 参数用于验证授权码流程的发起端和接受端是否为同一个客户端,以防止OAuth-Server账号伪装攻击。
|
||||
|
||||
授权流程发起端必须保证:
|
||||
- state 参数必须足够随机,不可被预测。
|
||||
- state 参数与授权码流程发起客户端 一 一 对 应,授权流程发起时创建的 state 必须与接受时返回的 state 值一致。
|
||||
- 安全起见,一个 state 参数只允许使用一次。
|
||||
|
||||
|
@ -158,6 +158,17 @@ public interface SaOAuth2Dao {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 持久化:state
|
||||
* @param state /
|
||||
*/
|
||||
default void saveState(String state) {
|
||||
if( ! SaFoxUtil.isEmpty(state)) {
|
||||
long ttl = SaOAuth2Manager.getServerConfig().getCodeTimeout();
|
||||
getSaTokenDao().set(splicingStateSaveKey(state), state, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------- delete数据
|
||||
|
||||
@ -262,6 +273,14 @@ public interface SaOAuth2Dao {
|
||||
getSaTokenDao().delete(splicingGrantScopeKey(clientId, loginId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除:state记录
|
||||
* @param state /
|
||||
*/
|
||||
default void deleteGrantScope(String state) {
|
||||
getSaTokenDao().delete(splicingStateSaveKey(state));
|
||||
}
|
||||
|
||||
|
||||
// ------------------- get 数据
|
||||
|
||||
@ -372,6 +391,18 @@ public interface SaOAuth2Dao {
|
||||
return SaOAuth2Manager.getDataConverter().convertScopeStringToList(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取:state
|
||||
* @param state /
|
||||
* @return /
|
||||
*/
|
||||
default String getState(String state) {
|
||||
if(SaFoxUtil.isEmpty(state)) {
|
||||
return null;
|
||||
}
|
||||
return getSaTokenDao().get(splicingStateSaveKey(state));
|
||||
}
|
||||
|
||||
|
||||
// ------------------- 拼接key
|
||||
|
||||
@ -469,6 +500,15 @@ public interface SaOAuth2Dao {
|
||||
return getSaTokenConfig().getTokenName() + ":oauth2:grant-scope:" + clientId + ":" + loginId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接key:state 参数持久化
|
||||
* @param state /
|
||||
* @return key
|
||||
*/
|
||||
default String splicingStateSaveKey(String state) {
|
||||
return getSaTokenConfig().getTokenName() + ":oauth2:state:" + state;
|
||||
}
|
||||
|
||||
|
||||
// -------- bean 对象代理
|
||||
|
||||
|
@ -91,4 +91,10 @@ public interface SaOAuth2DataGenerate {
|
||||
*/
|
||||
void revokeAccessToken(String accessToken);
|
||||
|
||||
/**
|
||||
* 检查 state 是否被重复使用
|
||||
* @param state /
|
||||
*/
|
||||
void checkState(String state);
|
||||
|
||||
}
|
||||
|
@ -245,6 +245,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
public String buildRedirectUri(String redirectUri, String code, String state) {
|
||||
String url = SaFoxUtil.joinParam(redirectUri, SaOAuth2Consts.Param.code, code);
|
||||
if( ! SaFoxUtil.isEmpty(state)) {
|
||||
checkState(state);
|
||||
url = SaFoxUtil.joinParam(url, SaOAuth2Consts.Param.state, state);
|
||||
}
|
||||
return url;
|
||||
@ -261,6 +262,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
public String buildImplicitRedirectUri(String redirectUri, String token, String state) {
|
||||
String url = SaFoxUtil.joinSharpParam(redirectUri, SaOAuth2Consts.Param.token, token);
|
||||
if( ! SaFoxUtil.isEmpty(state)) {
|
||||
checkState(state);
|
||||
url = SaFoxUtil.joinSharpParam(url, SaOAuth2Consts.Param.state, state);
|
||||
}
|
||||
return url;
|
||||
@ -291,5 +293,18 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
dao.deleteRefreshTokenIndex(at.clientId, at.loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 state 是否被重复使用
|
||||
* @param state /
|
||||
*/
|
||||
@Override
|
||||
public void checkState(String state) {
|
||||
String value = SaOAuth2Manager.getDao().getState(state);
|
||||
if(SaFoxUtil.isNotEmpty(value)) {
|
||||
throw new SaOAuth2Exception("多次请求的 state 不可重复: " + state);
|
||||
}
|
||||
SaOAuth2Manager.getDao().saveState(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user