改装和授权标头
Posted
技术标签:
【中文标题】改装和授权标头【英文标题】:Refit and authorization header 【发布时间】:2019-03-24 01:21:35 【问题描述】:目前,我正在向我的请求添加一个授权标头,如下所示:
文件:SomeFile.cs
public interface ITestApi
[Get("/api/test/id")]
Task<string> GetTest([Header("Authorization")] string authorization, int id);
[Get("/api/tests/")]
Task<string> GetTests([Header("Authorization")] string authorization);
文件:SomeOtherFile.cs
var username = "xxx";
var password = "yyy";
var authHeader = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
var baseAddress = "https://my.test.net";
ITestApi myApi = RestService.For<ITestApi>(baseAddress);
int id = 123;
var test= myApi.GetTest(authHeader, id);
var tests = myApi.GetTests(authHeader);
有没有办法在全局范围内设置 authHeader,这样我就不必将它作为参数传递给每个调用? (我使用的是改装版本 4.6.48)。换句话说,我希望能够像这样进行调用:
var test= myApi.GetTest(id);
var tests = myApi.GetTests();
【问题讨论】:
【参考方案1】:我找到了解决办法:
[Headers("Authorization: Basic")]
public interface ITestApi
[Get("/api/test/id")]
Task<string> GetTest(int id);
[Get("/api/tests/")]
Task<string> GetTests();
var username = "xxx";
var password = "yyy";
var authHeader = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
var baseAddress = "https://my.test.net";
var refitSettings = new RefitSettings()
AuthorizationHeaderValueGetter = () => Task.FromResult(authHeader)
;
ITestApi myApi = RestService.For<ITestApi>(baseAddress, refitSettings);
int id = 123;
var test= myApi.GetTest(id);
var tests = myApi.GetTests();
【讨论】:
太棒了!这里使AuthorizationHeaderValueGetter
部分工作而不被忽略的重要部分是接口上的属性。 [Headers("Authorization: Basic")]
必须存在,包括其中的 : <scheme>
部分,以便 Refit 调用 AuthorizationHeaderValueGetter
。
如果我们想要一个动态的授权方案怎么办?本例中的“基本”。【参考方案2】:
thd 的回答对我不起作用,因为 Refit 当前是 simply ignoring AuthorizationHeaderValueGetter
并且请求不包含身份验证标头。
我可以通过为我的HttpClient
提供默认身份验证标头来使其工作:
string token = await GetTokenAsync().ConfigureAwait(false);
string endpointUrl = Environment.GetEnvironmentVariable(endpointVariable) ??
defaultEndpointUrl ?? DefaultEndpointUrl;
var client = new HttpClient(new HttpClientHandler())
BaseAddress = new Uri(endpointUrl)
;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
//TODO: remove as this is ignored anyway
//var refitSettings = new RefitSettings
//
// AuthorizationHeaderValueGetter = () => Task.FromResult($"token")
//;
var builder = RequestBuilder.ForType<TApiClient>();
return RestService.For(client, builder);
GetTokenAsync 如下所示:
public static async Task<string> GetAccessTokenAsync()
// theoretically the token could have expired during the tests, but there is very low chance
// so returning the same token if one was generated
lock (SyncLock)
if (!string.IsNullOrWhiteSpace(Token))
return Token;
var client = new HttpClient();
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
Address = $"IdentityServerUrl/connect/token",
ClientId = "MY_CLIENT_APITEST",
ClientSecret = IdentityServerPass,
Scope = "api.read"
).ConfigureAwait(false);
tokenResponse.HttpResponse.EnsureSuccessStatusCode();
lock (SyncLock)
Token = tokenResponse.AccessToken;
return Token;
【讨论】:
并使用 OAuth 令牌:grant_type=client_credentials &client_id=example_client_id &client_secret=example_client_secret &scope=user.read
?
什么是GetTokenAsync?
@Kiquenet 用于从认证服务器获取有效令牌。
@Kiquenet 我终于记得搜索此代码并将其添加到答案中。
太棒了!你是我的偶像【参考方案3】:
改装改变了它的方法。现在它使用默认的 .NET HttpHandler
var handler = new AuthHandler(credentials.Username, credentials.Password);
var githubApi = RestService.For<IGithubApi>(new HttpClient(handler)
BaseAddress = new Uri("https://api.github.com")
);
public class AuthHandler : HttpClientHandler
private readonly string _username;
private readonly string _password;
public AuthHandler(string username,
string password)
_username = username;
_password = password;
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
request.Headers.Add("User-Agent", "<your user name or app name>");
request.Headers.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(
$"_username:_password")));
return await base.SendAsync(request, cancellationToken)
.ConfigureAwait(false);
【讨论】:
我无法让它工作。似乎 refit 删除了标题中的授权。在没有 DI 的 Xamarin 上测试,直接。有什么建议吗?以上是关于改装和授权标头的主要内容,如果未能解决你的问题,请参考以下文章