我正在尝试使用RestSharp向API发出请求。通过将请求重定向到登录服务器,使用基本凭据进行身份验证,获取cookie,然后重定向回API来保护此API。我恐怕无法控制这一点。
所以请求的顺序是:
Request Response
---------------------------------------------------------------------------------
1. GET http api server 302 Found to login server
2. GET https login server 401 Unauthorized
3. GET https login server with basic credentials 302 Found to api server with cookies
4. GET http api server with cookies 200 OK
我正在尝试使用RestSharp执行此操作。这是我的代码:
var client = new RestClient("api server")
{
Authenticator = new HttpBasicAuthenticator("username", "password")
};
var request = new RestRequest("api path", Method.GET);
var result = client.Execute<TResult>(request).Data;
授权标头仅在第一个请求时发送。它不遵循任何重定向。
有没有办法让RestSharp只将凭据发送到登录服务器?
答案 0 :(得分:3)
它总是不去。在发布到堆栈溢出后找到解决方案。
https://github.com/restsharp/RestSharp/issues/414
我必须构建一个自定义的System.Net.IAuthenticationModule,而不是在RestClient上使用IAuthenticator。这是我的解决方案:
我的RestSharp身份验证器
public class MyAuthenticator : IAuthenticator
{
private readonly CredentialCache _credentials = new CredentialCache();
public MyAuthenticator(Uri loginServerUrl, string username, string password)
{
if (loginServerUrl == null)
{
throw new ArgumentNullException("loginServerUrl");
}
__registerAuthenticationModule(loginServerUrl);
_credentials.Add(loginServerUrl, MyAuthenticationModule.TheAuthenticationType, new NetworkCredential(username, password, loginServerUrl.Host));
}
private static MyAuthenticationModule __registerAuthenticationModule(Uri loginServerUrl)
{
IEnumerator registeredModules = AuthenticationManager.RegisteredModules;
MyAuthenticationModule authenticationModule;
while (registeredModules.MoveNext())
{
object current = registeredModules.Current;
if (current is MyAuthenticationModule)
{
authenticationModule = (MyAuthenticationModule)current;
if (authenticationModule.LoginServerUrl.Equals(loginServerUrl))
{
return authenticationModule;
}
}
}
authenticationModule = new MyAuthenticationModule(loginServerUrl);
AuthenticationManager.Register(authenticationModule);
return authenticationModule;
}
public void Authenticate(IRestClient client, IRestRequest request)
{
request.Credentials = _credentials;
}
}
我的.NET身份验证模块
public class MyAuthenticationModule : IAuthenticationModule
{
internal const string TheAuthenticationType = "MyAuthentication";
private readonly CredentialCache _credentialCache = new CredentialCache();
private readonly Uri _loginServerUrl;
internal CredentialCache CredentialCache
{
get
{
return _credentialCache;
}
}
internal Uri LoginServerUrl
{
get
{
return _loginServerUrl;
}
}
internal MyAuthenticationModule(Uri loginServerurl)
{
if (loginServerurl == null)
{
throw new ArgumentNullException("loginServerUrl");
}
_loginServerUrl = loginServerurl;
}
public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
{
Authorization result = null;
if (request == null || credentials == null)
{
result = null;
}
else
{
NetworkCredential creds = credentials.GetCredential(LoginServerUrl, TheAuthenticationType);
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(string.Format("{0}:{1}", creds.UserName, creds.Password)));
result = new Authorization(string.Format("Basic {0}", token));
}
return result;
}
public string AuthenticationType
{
get { return TheAuthenticationType; }
}
public bool CanPreAuthenticate
{
get { return false; }
}
public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
{
return null;
}
}
像这样添加到RestSharp客户端
var client = new RestClient(commonApiUrl)
{
Authenticator = new MyAuthenticator(loginServerUrl, username, password)
};
答案 1 :(得分:0)
您可以在Authenticate方法中为请求分配CredentialsCache对象。 将这些凭据传递给请求会向请求表明您允许使用它们,即使对于后续请求(重定向)也是如此。
从此 msdn article:
重定向时,CredentialCache不会从Credentials属性中删除,因为WebRequest知道您允许发送凭据的位置。您还可以通过将缓存分配给后续请求来重用缓存。
所以RestSharp BasicAuthenticator实现可能如下所示:
public class BasicAuthenticator : IAuthenticator
{
private readonly string _baseUrl;
private readonly string _userName;
private readonly string _password;
private readonly CredentialCache _credentialCache;
public BasicAuthenticator(string baseUrl, string userName, string password)
{
_baseUrl = baseUrl;
_userName = userName;
_password = password;
_credentialCache = new CredentialCache
{
{new Uri(_baseUrl), "Basic", new NetworkCredential(_userName, _password)}
};
}
public void Authenticate(IRestClient client, IRestRequest request)
{
request.Credentials = _credentialCache;
if (request.Parameters.Any(parameter =>
parameter.Name.Equals("Authorization", StringComparison.OrdinalIgnoreCase)))
{
return;
}
request.AddParameter("Authorization", GetBasicAuthHeaderValue(), ParameterType.HttpHeader);
}
private string GetBasicAuthHeaderValue()
{
return string.Format("Basic {0}",
Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}",
_userName, _password))));
}
}