繁体   English   中英

如何通过桌面/控制台应用程序使用带有不记名令牌的 ASP.NET Web API 2.0

[英]How to consume ASP.NET Web API 2.0 with bearer token via a desktop/console application

我有一个使用 ASP.NET Web API 的控制台/winform(非浏览器)应用程序。 我已经实现了基于令牌的身份验证来保护我的 web api,并且需要找出检索令牌的最佳位置,因为我已经使用HttpClientHelper类遵循存储库模式?

获取令牌:

private static string GetToken(string url, string userName, string password)
{
    var pairs = new List<KeyValuePair<string, string>>
    {
        new KeyValuePair<string, string>( "grant_type", "password" ), 
        new KeyValuePair<string, string>( "username", userName ), 
        new KeyValuePair<string, string> ( "Password", password )
    };

    var content = new FormUrlEncodedContent(pairs);

    ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

    using(var client = new HttpClient())
    {
        var response = client.PostAsync(url + "Token", content).Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

HttpClient 帮助程序:

public sealed class HttpClientHelper<T, TResourceIdentifier> : IDisposable where T : class
{
        #region Constructors

        public HttpClientHelper(string serviceBaseAddress, string addressSuffix, string token)
        {
            _serviceBaseAddress = serviceBaseAddress;
            _addressSuffix = addressSuffix;
            _token = token
            _httpClient = MakeHttpClient();
        }

        #endregion

        #region CRUD

        public async Task<IEnumerable<T>> GetManyAsync()
        {
            var responseMessage = await _httpClient.GetAsync(_addressSuffix);

            if (responseMessage.IsSuccessStatusCode)
                return await responseMessage.Content.ReadAsAsync<IEnumerable<T>>();

            return null;
        }

        // Other CRUD operations

        #endregion

        #region Private Methods

        private HttpClient MakeHttpClient()
        {
            _httpClient = new HttpClient
            {
                BaseAddress = new Uri(_serviceBaseAddress),
                MaxResponseContentBufferSize = int.MaxValue,
                DefaultRequestHeaders = {Authorization = new AuthenticationHeaderValue("bearer", token)}
            };

            // Other settings

            return _httpClient;
        }

        #region IDisposable Members

        private void Dispose(bool disposing)
        {
            if (_disposed || !disposing) return;

            if (_httpClient != null)
            {
                var hc = _httpClient;
                _httpClient = null;
                hc.Dispose();
            }

            _disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~HttpClientHelper()
        {
            Dispose(false);
        }

        #endregion IDisposable Members
    }
}

我的通用类:

internal class GenericRepository<T, TResourceIdentifier> : IDisposable, IGenericRepository<T, TResourceIdentifier>  where T : class
{
    private bool _disposed;
    protected HttpClientHelper<T, TResourceIdentifier> Client;

    protected GenericRepository(string serviceBaseAddress, string addressSuffix, string token)
    {
        Client = new HttpClientHelper<T, TResourceIdentifier>(serviceBaseAddress, addressSuffix, token);
    }

    public async Task<IEnumerable<T>> GetManyAsync()
    {
        return await Client.GetManyAsync();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (_disposed || !disposing) return;

        if (Client != null)
        {
            var mc = Client;
            Client = null;
            mc.Dispose();
        }

        _disposed = true;
    }
}

自定义存储库类示例:

internal class CustomerRepository : GenericRepository<Customer, int> , ICustomerRepository
{
    internal CustomerRepository() : base(Properties.Settings.Default.Url, "Customers/", ***TOKEN***)
    {
    }
}

用法:

private readonly ICustomerRepository _customerRepository = new CustomerRepository();

private async Task<Customer> GetCustomer(int customerId)   
{
    var customer = new Customer();

    try
    {
        customer = await _customerRepository.GetAsync(customerId);
    }
    catch (Exception ex)
    {
        // Log the error
    }

    return customer;
}

在声明我的 IRepository 时,我究竟在哪里获取/分配令牌而不会出现 nullexception 错误?

在任何情况下,您都不应该每次都实例化一个新的HttpClient IDisposable可能会让你认为你应该这样做,但它是一种反模式。 检查https://softwareengineering.stackexchange.com/questions/330364/should-we-create-a-new-single-instance-of-httpclient-for-all-requests以获取有关此事的大量资源。

与令牌相同的事情。 只要您的令牌处于活动状态,就可以使用它。 使用安全问题应由身份提供者和超时解决。 这就是为什么有一个刷新令牌来处理令牌过期的原因。

https://oauth.net/2/grant-types/refresh-token/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM