C# 如何使用RestSharp为承载令牌实现自定义IAAuthenticationModule
我使用RestSharp向使用承载令牌身份验证的API发出请求。大多数请求按预期运行,但有一个特定的端点总是将请求重定向到动态位置。当发生此重定向时,授权标头将丢失(根据设计),从而导致错误的请求 我对这个问题做了一些调查,发现了一个类似的问题,但是我制作的自定义AuthenticationModule从未调用过Authenticate函数 我是否在设置中遗漏了一些明显的阻止使用身份验证模块的内容,或者是否有其他情况发生 谢谢 我的验证器类:C# 如何使用RestSharp为承载令牌实现自定义IAAuthenticationModule,c#,.net,restsharp,C#,.net,Restsharp,我使用RestSharp向使用承载令牌身份验证的API发出请求。大多数请求按预期运行,但有一个特定的端点总是将请求重定向到动态位置。当发生此重定向时,授权标头将丢失(根据设计),从而导致错误的请求 我对这个问题做了一些调查,发现了一个类似的问题,但是我制作的自定义AuthenticationModule从未调用过Authenticate函数 我是否在设置中遗漏了一些明显的阻止使用身份验证模块的内容,或者是否有其他情况发生 谢谢 我的验证器类: public class AdpAuthentica
public class AdpAuthenticator : IAuthenticator
{
/// <summary>
/// The current access token for making requests to the API.
/// </summary>
private static string AccessToken { get; set; }
/// <summary>
/// When the current access token expires.
/// </summary>
private static DateTime TokenExpiresOn { get; set; }
private static CredentialCache CredentialCache { get; set; }
/// <summary>
/// Singleton instance for making requests for access tokens.
/// </summary>
private static IRestClient AuthenticationClient { get; set; }
/// <summary>
/// Singleton instance of the request for obtaining access tokens.
/// </summary>
private static IRestRequest AuthenticationRequest { get; set; }
/// <summary>
/// Construct a new AdpAuthenticator.
/// </summary>
/// <param name="adpClientId"></param>
/// <param name="adpClientSecret"></param>
/// <param name="adpCertPath"></param>
public AdpAuthenticator(string adpClientId, string adpClientSecret, string adpCertPath)
{
if (string.IsNullOrWhiteSpace(adpClientId)) throw new ArgumentNullException("Passed adpClientId was empty or null.");
if (string.IsNullOrWhiteSpace(adpClientSecret)) throw new ArgumentNullException("Passed adpClientSecret was empty or null.");
if (CredentialCache == null)
{
CredentialCache = new CredentialCache
{
{new Uri("https://api.adp.com"), "Basic", new NetworkCredential(adpClientId, adpClientSecret) }
};
}
if (AuthenticationClient == null)
{
X509Certificate2Collection certificateCollection;
X509Certificate2 certificate = new X509Certificate2(adpCertPath);
certificateCollection = new X509Certificate2Collection
{
certificate
};
AuthenticationClient = new RestClient("https://api.adp.com")
{
ClientCertificates = certificateCollection,
Authenticator = new HttpBasicAuthenticator(adpClientId, adpClientSecret)
};
AuthenticationClient.UseSerializer(new JsonNetSerializer());
}
if (AuthenticationRequest == null)
{
AuthenticationRequest = new RestRequest("auth/oauth/v2/token", Method.POST)
{
Credentials = CredentialCache
};
AuthenticationRequest.AddOrUpdateParameter("grant_type", "client_credentials", ParameterType.QueryString);
}
RegisterAuthenticationModule(new Uri("https://api.adp.com/"));
}
/// <summary>
/// Authenticate a request.
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
public void Authenticate(IRestClient client, IRestRequest request)
{
//If accessToken is null or expired, get a new one.
if (!HasValidToken())
{
RefreshAccessToken();
}
//request.AddOrUpdateParameter("Authorization", AccessToken, ParameterType.HttpHeader);
//var newCache = new CredentialCache
//{
// {new Uri("https://api.adp.com/"), "Bearer", new NetworkCredential(AccessToken, "") }
//};
var newCache = new CredentialCache();
newCache.Add(new Uri("https://api.adp.com/"), AdpAuthenticationModule.TheAuthenticationType, new NetworkCredential(AccessToken, ""));
request.Credentials = newCache;
//request.AddOrUpdateParameter("Authorization", "Bearer " + AccessToken, ParameterType.HttpHeader);
}
private void RefreshAccessToken()
{
try
{
var response = AuthenticationClient.Execute<AuthorizationResponse>(AuthenticationRequest);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new FailedAuthenticationException($"Authentication failed to refresh access token, returned with code {response.StatusCode}. Content: \"{response.Content}\".", null);
}
if (string.IsNullOrWhiteSpace(response.Data.access_token))
{
throw new Exception("Error: response returned during access token refresh gave Status 200 OK, but access_token returned was null or whitespace.");
}
AccessToken = response.Data.access_token;
if (response.Data.expires_in <= 0)
{
throw new Exception("Error: response returned during access token refresh gave Status 200 OK, but expires_in value returned was <=0.");
}
TokenExpiresOn = DateTime.Now.AddSeconds(response.Data.expires_in);
}
catch (FailedAuthenticationException)
{
throw;
}
catch (Exception e)
{
throw new FailedAuthenticationException($"Authentication failed to refresh access token, see inner exception details.", e);
}
}
/// <summary>
/// Returns whether the current access token is valid.
/// </summary>
/// <returns>False if token is null or has 10 or less minutes until expiry; else returns true.</returns>
public bool HasValidToken()
{
return !string.IsNullOrEmpty(AccessToken) && DateTime.Now.CompareTo(TokenExpiresOn.AddMinutes(-10.0)) < 0;
}
private static AdpAuthenticationModule RegisterAuthenticationModule(Uri loginServerUrl)
{
var registeredModules = AuthenticationManager.RegisteredModules;
AdpAuthenticationModule authenticationModule;
while (registeredModules.MoveNext())
{
object current = registeredModules.Current;
if (current is AdpAuthenticationModule)
{
authenticationModule = (AdpAuthenticationModule)current;
if (authenticationModule.LoginServerUrl.Equals(loginServerUrl))
{
return authenticationModule;
}
}
}
authenticationModule = new AdpAuthenticationModule(loginServerUrl);
AuthenticationManager.Register(authenticationModule);
return authenticationModule;
}
}
公共类AdpAuthenticator:IAAuthenticator
{
///
///用于向API发出请求的当前访问令牌。
///
私有静态字符串AccessToken{get;set;}
///
///当当前访问令牌过期时。
///
私有静态日期时间令牌expireson{get;set;}
私有静态凭证缓存凭证缓存{get;set;}
///
///用于请求访问令牌的单例实例。
///
私有静态IRestClient身份验证客户端{get;set;}
///
///获取访问令牌的请求的单例实例。
///
私有静态IRestRequest AuthenticationRequest{get;set;}
///
///构造一个新的AdpAuthenticator。
///
///
///
///
公共AdpAuthenticator(字符串adpClientId、字符串adpClientSecret、字符串adpCertPath)
{
if(string.IsNullOrWhiteSpace(adpClientId))抛出新的ArgumentNullException(“传递的adpClientId为空或null”);
if(string.IsNullOrWhiteSpace(adpClientSecret))抛出新的ArgumentNullException(“传递的adpClientSecret为空或null”);
if(CredentialCache==null)
{
CredentialCache=新的CredentialCache
{
{新Uri(“https://api.adp.com“”,“基本”,新网络凭据(adpClientId,adpClientSecret)}
};
}
如果(AuthenticationClient==null)
{
X509证书2收集证书收集;
X509Certificate2证书=新的X509Certificate2(adpCertPath);
certificateCollection=新X509Certificate2Collection
{
证明书
};
AuthenticationClient=新的RestClient(“https://api.adp.com")
{
ClientCertificates=certificateCollection,
Authenticator=新的HttpBasicAuthenticator(adpClientId,adpClientSecret)
};
AuthenticationClient.UseSerializer(新的JsonNetSerializer());
}
如果(AuthenticationRequest==null)
{
AuthenticationRequest=new RestRequest(“auth/oauth/v2/token”,Method.POST)
{
凭证=凭证凭证凭证
};
AuthenticationRequest.AddOrUpdateParameter(“授权类型”、“客户端凭据”、参数类型.QueryString);
}
RegisterAuthenticationModule(新Uri(“https://api.adp.com/"));
}
///
///对请求进行身份验证。
///
///
///
公共无效身份验证(IRestClient客户端、IRestRequest请求)
{
//如果accessToken为null或已过期,请获取新的accessToken。
如果(!HasValidToken())
{
RefreshAccessToken();
}
//AddOrUpdateParameter(“授权”,AccessToken,ParameterType.HttpHeader);
//var newCache=新凭证缓存
//{
//{新Uri(“https://api.adp.com/“”,“承载者”,新网络凭证(AccessToken,“”)
//};
var newCache=newcredentialcache();
添加(新Uri(“https://api.adp.com/“”,AdpAuthenticationModule.TheAuthenticationType,新网络凭据(AccessToken“”);
request.Credentials=newCache;
//request.AddOrUpdateParameter(“授权”、“承载者”+AccessToken,ParameterType.HttpHeader);
}
私有void RefreshAccessToken()
{
尝试
{
var response=AuthenticationClient.Execute(AuthenticationRequest);
if(response.StatusCode!=System.Net.HttpStatusCode.OK)
{
抛出新的FailedAuthenticationException($”身份验证未能刷新访问令牌,返回代码{response.StatusCode}。内容:\“{response.Content}\”,null);
}
if(string.IsNullOrWhiteSpace(response.Data.access_令牌))
{
抛出新异常(“错误:在访问令牌刷新期间返回的响应给出了状态200 OK,但返回的访问令牌为null或空白。”);
}
AccessToken=response.Data.access\u令牌;
验证类型中的if(response.Data.expires);
公共静态字符串TheAuthenticationType=>“AdpAuthentication”;
///
///返回false,因为此IAuthenticationModule无法预验证。
///
公共bool CanPreAuthenticate=>false;
private readonly CredentialCache CredentialCache=new CredentialCache();
私有只读Uri登录服务器URL;
内部凭证凭证凭证凭证凭证凭证凭证凭证
{
得到
{
返回凭证;
}
}
内部Uri登录服务器URL
{
得到
{
返回登录服务器URL;
}
}
内部AdpAuthenticationModule(Uri登录服务器URL)
{
this.loginServerUrl=loginServerUrl??抛出新的ArgumentNullException(“AdpAuthenticationModule.loginServerUrl”);
}
///
///生成并返回请求的对象。
///
///
///
///
///
公共授权身份验证(字符串质询、WebRequest请求、ICredentials凭据)
{
授权结果=空;
if(请求!=null&&credentials!=null)
{
public class AdpAuthenticationModule : IAuthenticationModule
{
/// <summary>
/// The name of the custom authentication type.
/// </summary>
public string AuthenticationType => TheAuthenticationType;
public static string TheAuthenticationType => "AdpAuthentication";
/// <summary>
/// Returns false, as this IAuthenticationModule cannot pre-authenticate.
/// </summary>
public bool CanPreAuthenticate => false;
private readonly CredentialCache credentialCache = new CredentialCache();
private readonly Uri loginServerUrl;
internal CredentialCache CredentialCache
{
get
{
return credentialCache;
}
}
internal Uri LoginServerUrl
{
get
{
return loginServerUrl;
}
}
internal AdpAuthenticationModule(Uri loginServerUrl)
{
this.loginServerUrl = loginServerUrl ?? throw new ArgumentNullException("AdpAuthenticationModule.loginServerUrl");
}
/// <summary>
/// Builds and returns a <see cref="Authorization"/> object for a request.
/// </summary>
/// <param name="challenge"></param>
/// <param name="request"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
{
Authorization result = null;
if (request != null && credentials != null)
{
NetworkCredential creds = credentials.GetCredential(LoginServerUrl, AuthenticationType);
if (creds == null)
{
return null;
}
ICredentialPolicy policy = AuthenticationManager.CredentialPolicy;
if (policy != null && !policy.ShouldSendCredential(LoginServerUrl, request, creds, this))
{
return null;
}
string token = Convert.ToBase64String(Encoding.UTF8.GetBytes(creds.UserName));
result = new Authorization(string.Format("Bearer {0}", token));
}
return result;
}
/// <summary>
/// Returns null, since this IAuthenticationModule cannot pre-authenticate.
/// </summary>
/// <param name="request"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
{
return null;
}
}
AuthenticationManager.Register(new AdpAuthenticationModule());