【问题标题】: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();

【问题讨论】:

    标签: c# asp.net-authorization refit


    【解决方案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")] 必须存在,包括其中的 : &lt;scheme&gt; 部分,以便 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 &amp;client_id=example_client_id &amp;client_secret=example_client_secret &amp;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 上测试,直接。有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 2012-04-18
    • 2016-06-02
    • 2017-01-03
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    相关资源
    最近更新 更多