扩展Auth.AuthProviderPluginClass时如何自定义state参数?
自定义AuthProvider State变量问题解决方案
核心原因
OAuth的state参数用于防范CSRF攻击,不管是Salesforce的AuthProvider框架还是第三方OAuth服务,都要求state必须是随机生成、可验证的有效取值:
- 移除
state会触发第三方服务的必填校验,导致Remote_Error - 使用固定虚拟值(如
test)会因无法通过验证逻辑,触发No_Oauth_State错误
解决方法
1. 利用Salesforce框架自动处理State(推荐)
继承Auth.AuthProviderPluginClass的自定义类,直接调用父类方法即可让框架自动完成state的生成、会话存储和回调验证,无需手动实现复杂逻辑:
自定义AuthProvider代码实现
public class CustomAuthProvider extends Auth.AuthProviderPluginClass { public override PageReference initiate(Map<String, String> providerConfiguration, String state) { // 调用父类方法,自动生成并处理state PageReference authPage = super.initiate(providerConfiguration, state); // 添加自定义授权参数(如scope、重定向地址) authPage.getParameters().put('scope', providerConfiguration.get('Scope__c')); authPage.getParameters().put('redirect_uri', providerConfiguration.get('Redirect_URI__c')); return authPage; } public override Auth.AuthProviderPluginResult handleCallback(Map<String, String> providerConfiguration, Map<String, String> callbackParameters) { // 父类自动完成state验证,无需手动处理 Auth.AuthProviderPluginResult baseResult = super.handleCallback(providerConfiguration, callbackParameters); // 在此添加自定义token解析、用户映射等逻辑 return baseResult; } }
调用initiate的代码修改
无需手动传入固定state,直接传null让框架自动生成:
// 获取MDT记录信息 AuthCredential__mdt authCredentialMDT = [SELECT Id, Client_Id__c, Auth_URL__c, Scope__c, Redirect_URI__c FROM AuthCredential__mdt WHERE DeveloperName =:authProviderDeveloperName]; Map<String, String> stringMap = new Map<String, String>(); Map<String, Object> objectMap = (Map<String, Object>)(JSON.deserializeUntyped(JSON.serialize(authCredentialMDT))); for(String key : objectMap.keySet()) {stringMap.put(key, String.valueOf(objectMap.get(key)));} // 获取授权页面URL,传入null让框架自动生成state CustomAuthProvider authMethod = new CustomAuthProvider(); PageReference newPage = authMethod.initiate(stringMap, null); result = newPage.getUrl();
2. 自定义State生成与验证(完全控制场景)
如果需要自定义state的生成规则,必须确保state在授权发起时存储到会话,回调时取出验证:
自定义AuthProvider代码实现
public class CustomAuthProvider extends Auth.AuthProviderPluginClass { public override PageReference initiate(Map<String, String> providerConfiguration, String state) { // 生成随机唯一的state值 String customState = String.valueOf(Crypto.getRandomLong()); // 将state存储到用户会话,用于后续验证 ApexPages.currentPage().getSession().put('CustomAuth_State', customState); // 构建授权URL并携带自定义state String authUrl = providerConfiguration.get('Auth_URL__c'); PageReference authPage = new PageReference(authUrl); authPage.getParameters().putAll(new Map<String, String>{ 'client_id' => providerConfiguration.get('Client_Id__c'), 'redirect_uri' => providerConfiguration.get('Redirect_URI__c'), 'scope' => providerConfiguration.get('Scope__c'), 'state' => customState }); return authPage; } public override Auth.AuthProviderPluginResult handleCallback(Map<String, String> providerConfiguration, Map<String, String> callbackParameters) { // 取出会话中存储的state String storedState = (String)ApexPages.currentPage().getSession().get('CustomAuth_State'); String receivedState = callbackParameters.get('state'); // 验证state有效性 if (String.isBlank(storedState) || !storedState.equals(receivedState)) { throw new Auth.AuthProviderException('No_Oauth_State: State was not valid'); } // 清除会话中的state,避免重复使用 ApexPages.currentPage().getSession().remove('CustomAuth_State'); // 后续处理token获取、用户映射等逻辑 return new Auth.AuthProviderPluginResult(...); } }
3. 额外校验项
- 确认Auth.Provider、Named Credential中的
Redirect URI与MDT记录、第三方OAuth服务的配置完全一致,否则会触发state验证失败 - 检查通过Tooling API创建的Auth Provider记录,确保
Consumer Key、Consumer Secret等核心配置无误
内容的提问来源于stack exchange,提问作者islandtimesfdcdeveloper
相关产品推荐
相关产品推荐

