mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-05-02 20:02:45 +08:00
新增自定义 scope 处理器支持
This commit is contained in:
parent
2b46d27b87
commit
281985bfdb
@ -3,6 +3,8 @@ package com.pj.oauth2;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.ejlchina.okhttps.OkHttps;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.pj.utils.SoMap;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -32,7 +34,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 根据Code码进行登录,获取 Access-Token 和 openid
|
||||
@RequestMapping("/codeLogin")
|
||||
public SaResult codeLogin(String code) {
|
||||
public SaResult codeLogin(String code) throws JsonProcessingException {
|
||||
// 调用Server端接口,获取 Access-Token 以及其他信息
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/token")
|
||||
.addBodyPara("grant_type", "authorization_code")
|
||||
@ -43,7 +45,7 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
@ -61,7 +63,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 根据 Refresh-Token 去刷新 Access-Token
|
||||
@RequestMapping("/refresh")
|
||||
public SaResult refresh(String refreshToken) {
|
||||
public SaResult refresh(String refreshToken) throws JsonProcessingException {
|
||||
// 调用Server端接口,通过 Refresh-Token 刷新出一个新的 Access-Token
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/refresh")
|
||||
.addBodyPara("grant_type", "refresh_token")
|
||||
@ -72,7 +74,7 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
@ -85,7 +87,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 模式三:密码式-授权登录
|
||||
@RequestMapping("/passwordLogin")
|
||||
public SaResult passwordLogin(String username, String password) {
|
||||
public SaResult passwordLogin(String username, String password) throws JsonProcessingException {
|
||||
// 模式三:密码式-授权登录
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/token")
|
||||
.addBodyPara("grant_type", "password")
|
||||
@ -97,7 +99,7 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
@ -115,7 +117,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 模式四:获取应用的 Client-Token
|
||||
@RequestMapping("/clientToken")
|
||||
public SaResult clientToken() {
|
||||
public SaResult clientToken() throws JsonProcessingException {
|
||||
// 调用Server端接口
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/client_token")
|
||||
.addBodyPara("grant_type", "client_credentials")
|
||||
@ -125,7 +127,7 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
@ -145,7 +147,7 @@ public class SaOAuthClientController {
|
||||
|
||||
// 根据 Access-Token 置换相关的资源: 获取账号昵称、头像、性别等信息
|
||||
@RequestMapping("/getUserinfo")
|
||||
public SaResult getUserinfo(String accessToken) {
|
||||
public SaResult getUserinfo(String accessToken) throws JsonProcessingException {
|
||||
// 调用Server端接口,查询开放的资源
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/userinfo")
|
||||
.addBodyPara("access_token", accessToken)
|
||||
@ -153,7 +155,7 @@ public class SaOAuthClientController {
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
System.out.println("返回结果: " + so);
|
||||
System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));
|
||||
|
||||
// code不等于200 代表请求失败
|
||||
if(so.getInt("code") != 200) {
|
||||
|
@ -24,7 +24,7 @@ public class SaOAuth2DataLoaderImpl implements SaOAuth2DataLoader {
|
||||
.setClientId("1001")
|
||||
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee")
|
||||
.setAllowUrl("*")
|
||||
.setContractScopes(Arrays.asList("userinfo"))
|
||||
.setContractScopes(Arrays.asList("userinfo", "openid"))
|
||||
.setIsAutoMode(true);
|
||||
}
|
||||
return null;
|
||||
|
@ -73,14 +73,11 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
|
||||
public AccessTokenModel convertCodeToAccessToken(CodeModel cm) {
|
||||
AccessTokenModel at = new AccessTokenModel();
|
||||
at.accessToken = SaOAuth2Manager.getDataLoader().randomAccessToken(cm.clientId, cm.loginId, cm.scopes);
|
||||
// at.refreshToken = randomRefreshToken(cm.clientId, cm.loginId, cm.scope);
|
||||
at.clientId = cm.clientId;
|
||||
at.loginId = cm.loginId;
|
||||
at.scopes = cm.scopes;
|
||||
at.openid = SaOAuth2Manager.getDataLoader().getOpenid(cm.clientId, cm.loginId);
|
||||
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(cm.clientId);
|
||||
at.expiresTime = System.currentTimeMillis() + (clientModel.getAccessTokenTimeout() * 1000);
|
||||
// at.refreshExpiresTime = System.currentTimeMillis() + (checkClientModel(cm.clientId).getRefreshTokenTimeout() * 1000);
|
||||
return at;
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,11 @@ package cn.dev33.satoken.oauth2.data.generate;
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
|
||||
import cn.dev33.satoken.oauth2.dao.SaOAuth2Dao;
|
||||
import cn.dev33.satoken.oauth2.data.convert.SaOAuth2DataConverter;
|
||||
import cn.dev33.satoken.oauth2.data.model.*;
|
||||
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
|
||||
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
import java.util.List;
|
||||
@ -68,6 +70,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
public AccessTokenModel generateAccessToken(String code) {
|
||||
|
||||
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
|
||||
SaOAuth2DataConverter dataConverter = SaOAuth2Manager.getDataConverter();
|
||||
|
||||
// 1、先校验
|
||||
CodeModel cm = dao.getCode(code);
|
||||
@ -78,8 +81,9 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
|
||||
dao.deleteRefreshToken(dao.getRefreshTokenValue(cm.clientId, cm.loginId));
|
||||
|
||||
// 3、生成token
|
||||
AccessTokenModel at = SaOAuth2Manager.getDataConverter().convertCodeToAccessToken(cm);
|
||||
RefreshTokenModel rt = SaOAuth2Manager.getDataConverter().convertAccessTokenToRefreshToken(at);
|
||||
AccessTokenModel at = dataConverter.convertCodeToAccessToken(cm);
|
||||
SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);
|
||||
RefreshTokenModel rt = dataConverter.convertAccessTokenToRefreshToken(at);
|
||||
at.refreshToken = rt.refreshToken;
|
||||
at.refreshExpiresTime = rt.expiresTime;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
package cn.dev33.satoken.oauth2.data.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.oauth2.function.strategy;
|
||||
|
||||
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 函数式接口:AccessTokenModel 加工
|
||||
*
|
||||
* <p> 参数:AccessTokenModel </p>
|
||||
* <p> 返回:无 </p>
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.35.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaScopeWorkFunction extends Consumer<AccessTokenModel> {
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.Api;
|
||||
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.GrantType;
|
||||
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.Param;
|
||||
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.ResponseType;
|
||||
import cn.dev33.satoken.oauth2.data.generate.SaOAuth2DataGenerate;
|
||||
import cn.dev33.satoken.oauth2.data.model.*;
|
||||
import cn.dev33.satoken.oauth2.data.model.other.ClientIdAndSecretModel;
|
||||
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
|
||||
@ -140,6 +141,7 @@ public class SaOAuth2ServerProcessor {
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaResponse res = SaHolder.getResponse();
|
||||
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
|
||||
SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();
|
||||
|
||||
// 1、如果尚未登录, 则先去登录
|
||||
if( ! getStpLogic().isLogin()) {
|
||||
@ -161,18 +163,19 @@ public class SaOAuth2ServerProcessor {
|
||||
return cfg.confirmView.apply(ra.clientId, ra.scopes);
|
||||
}
|
||||
|
||||
|
||||
// 6、判断授权类型
|
||||
// 如果是 授权码式,则:开始重定向授权,下放code
|
||||
if(ResponseType.code.equals(ra.responseType)) {
|
||||
CodeModel codeModel = SaOAuth2Manager.getDataGenerate().generateCode(ra);
|
||||
String redirectUri = SaOAuth2Manager.getDataGenerate().buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
|
||||
CodeModel codeModel = dataGenerate.generateCode(ra);
|
||||
String redirectUri = dataGenerate.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
|
||||
return res.redirect(redirectUri);
|
||||
}
|
||||
|
||||
// 如果是 隐藏式,则:开始重定向授权,下放 token
|
||||
if(ResponseType.token.equals(ra.responseType)) {
|
||||
AccessTokenModel at = SaOAuth2Manager.getDataGenerate().generateAccessToken(ra, false);
|
||||
String redirectUri = SaOAuth2Manager.getDataGenerate().buildImplicitRedirectUri(ra.redirectUri, at.accessToken, ra.state);
|
||||
AccessTokenModel at = dataGenerate.generateAccessToken(ra, false);
|
||||
String redirectUri = dataGenerate.buildImplicitRedirectUri(ra.redirectUri, at.accessToken, ra.state);
|
||||
return res.redirect(redirectUri);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.oauth2.scope.handler;
|
||||
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
|
||||
import cn.dev33.satoken.oauth2.scope.CommonScope;
|
||||
|
||||
/**
|
||||
* 所有OAuth2 权限处理器的父接口
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public class OpenIdScopeHandler implements SaOAuth2ScopeAbstractHandler {
|
||||
|
||||
/**
|
||||
* 获取所要处理的权限
|
||||
*/
|
||||
public String getHandlerScope() {
|
||||
return CommonScope.OPENID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所需要执行的方法
|
||||
*/
|
||||
public void work(AccessTokenModel at) {
|
||||
System.out.println("追加 openid " + at.accessToken);
|
||||
at.openid = SaOAuth2Manager.getDataLoader().getOpenid(at.clientId, at.loginId);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.oauth2.scope.handler;
|
||||
|
||||
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
|
||||
|
||||
/**
|
||||
* 所有OAuth2 权限处理器的父接口
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public interface SaOAuth2ScopeAbstractHandler {
|
||||
|
||||
/**
|
||||
* 获取所要处理的权限
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
String getHandlerScope();
|
||||
|
||||
/**
|
||||
* 所需要执行的方法
|
||||
*
|
||||
* @param at /
|
||||
*/
|
||||
default void work(AccessTokenModel at) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2020-2099 sa-token.cc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package cn.dev33.satoken.oauth2.strategy;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.oauth2.function.strategy.SaScopeWorkFunction;
|
||||
import cn.dev33.satoken.oauth2.scope.CommonScope;
|
||||
import cn.dev33.satoken.oauth2.scope.handler.OpenIdScopeHandler;
|
||||
import cn.dev33.satoken.oauth2.scope.handler.SaOAuth2ScopeAbstractHandler;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-Token OAuth2 相关策略
|
||||
*
|
||||
* @author click33
|
||||
* @since 1.39.0
|
||||
*/
|
||||
public final class SaOAuth2Strategy {
|
||||
|
||||
private SaOAuth2Strategy() {
|
||||
registerDefaultScopeHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例引用
|
||||
*/
|
||||
public static final SaOAuth2Strategy instance = new SaOAuth2Strategy();
|
||||
|
||||
|
||||
// ----------------------- 所有策略
|
||||
|
||||
/**
|
||||
* 权限处理器集合
|
||||
*/
|
||||
public Map<String, SaOAuth2ScopeAbstractHandler> scopeHandlerMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 注册所有默认的权限处理器
|
||||
*/
|
||||
public void registerDefaultScopeHandler() {
|
||||
scopeHandlerMap.put(CommonScope.OPENID, new OpenIdScopeHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个权限处理器
|
||||
*/
|
||||
public void registerScopeHandler(SaOAuth2ScopeAbstractHandler handler) {
|
||||
scopeHandlerMap.put(handler.getHandlerScope(), handler);
|
||||
// TODO 优化日志输出
|
||||
SaManager.getLog().info("新增权限处理器:" + handler.getHandlerScope());
|
||||
// SaTokenEventCenter.doRegisterAnnotationHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个权限处理器
|
||||
*/
|
||||
public void removeScopeHandler(String scope) {
|
||||
scopeHandlerMap.remove(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 scope 信息对一个 AccessTokenModel 进行加工处理
|
||||
*/
|
||||
public SaScopeWorkFunction workAccessTokenByScope = (at) -> {
|
||||
System.out.println("增强:" + at.accessToken);
|
||||
System.out.println("权限:" + at.scopes);
|
||||
// 遍历所有的权限处理器,如果此 AccessToken 具有这些权限,则开始加工
|
||||
if(at.scopes != null && !at.scopes.isEmpty()) {
|
||||
for (Map.Entry<String, SaOAuth2ScopeAbstractHandler> entry: scopeHandlerMap.entrySet()) {
|
||||
if(at.scopes.contains(entry.getKey())) {
|
||||
entry.getValue().work(at);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -47,16 +47,6 @@ public class SaOAuth2Template {
|
||||
return SaOAuth2Manager.getDataLoader().getClientModel(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ClientId 和 LoginId 获取openid
|
||||
* @param clientId 应用id
|
||||
* @param loginId 账号id
|
||||
* @return 此账号在此Client下的openid
|
||||
*/
|
||||
public String getOpenid(String clientId, Object loginId) {
|
||||
return SaOAuth2Manager.getDataLoader().getOpenid(clientId, loginId);
|
||||
}
|
||||
|
||||
// ------------------- 资源校验API
|
||||
/**
|
||||
* 根据id获取Client信息, 如果Client为空,则抛出异常
|
||||
|
Loading…
Reference in New Issue
Block a user