【问题标题】:How to implement REST API with OAuth 2.0 for multiple client access如何使用 OAuth 2.0 实现 REST API 以实现多客户端访问
【发布时间】:2016-08-26 18:23:03
【问题描述】:

我有如下要求使用 OAuth 2.0 和 Web Api 实现 REST API。

REST API 应该允许 - 创建、更新、查看和删除订单 - 创建、更新、查看和删除库存

API 应该能够被任何类型的外部客户端使用,例如 Web 应用程序、移动应用程序、Windows/Web 服务等。

允许外部客户的角色:订单管理、库存管理 外部客户的用户数据(角色、权限)不会由我们的系统管理。

注意:还可以有另外两个角色,例如 Internal 、 External 。因为外部用户不能使用删除功能。

订单和库存数据将在当前 Windows/桌面应用程序已使用的 SQL Server 数据库中进行管理。订单、库存来自新的 API 应该保存在同一个数据库中。

问题:

  1. 我可以使用哪种资助类型?
  2. 我应该如何管理外部客户端的数据(允许的角色、客户端 ID、令牌)?我需要为此使用单独的会员数据库吗?我可以将现有数据库与新表一起使用吗?

【问题讨论】:

标签: c# sql-server oauth-2.0 asp.net-web-api2 membership-provider


【解决方案1】:

您可以使用Microsoft.Owin.Security.OAuth 提供程序。请查看以下示例。

新建 Owin Startup 文件并更改 Configuration 方法如下

public void Configuration(IAppBuilder app)
{
    var oauthProvider = new OAuthAuthorizationServerProvider
    {
        OnGrantClientCredentials = async context =>
        {

            var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
            // based on clientId get roles and add claims
            claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "Developer"));
            claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "Developer2"));
            context.Validated(claimsIdentity);
        },
        OnValidateClientAuthentication = async context =>
        {
            string clientId;
            string clientSecret;
            // use context.TryGetBasicCredentials in case of passing values in header
            if (context.TryGetFormCredentials(out clientId, out clientSecret))
            {
                if (clientId == "clientId" && clientSecret == "secretKey")
                {
                    context.Validated(clientId);
                }
            }
        }
    };
    var oauthOptions = new OAuthAuthorizationServerOptions
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/accesstoken"),
        Provider = oauthProvider,
        AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(1),
        AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(3),
        SystemClock = new SystemClock()
    };
    app.UseOAuthAuthorizationServer(oauthOptions);
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

    var config = new HttpConfiguration();
    config.MapHttpAttributeRoutes();
    app.UseWebApi(config);
}

并像这样授权您的 API

[Authorize(Roles = "Developer")]
// GET: api/Tests
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

你可以像下面这样使用它,

string baseAddress = "http://localhost/";
var client = new HttpClient();

// you can pass the values in Authorization header or as form data
//var authorizationHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes("clientId:secretKey"));
//client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authorizationHeader);

var form = new Dictionary<string, string>
    {
        {"grant_type", "client_credentials"},
        {"client_id", "clientId"},
        {"client_secret", "secretKey"},
    };

var tokenResponse = client.PostAsync(baseAddress + "accesstoken", new FormUrlEncodedContent(form)).Result;
var token = tokenResponse.Content.ReadAsAsync<Token>(new[] { new JsonMediaTypeFormatter() }).Result;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
var authorizedResponse = client.GetAsync(baseAddress + "/api/Tests").Result;

Token.cs

internal class Token
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }

    [JsonProperty("token_type")]
    public string TokenType { get; set; }

    [JsonProperty("expires_in")]
    public int ExpiresIn { get; set; }

    [JsonProperty("refresh_token")]
    public string RefreshToken { get; set; }
}

回答您的问题

  1. 您可以使用client_credentials
  2. 在您自己的数据库和OnGrantClientCredentials 中为每个客户维护角色,只需通过客户 ID 获取角色并分配为声明。

【讨论】:

    【解决方案2】:
    1. Here是Grant为哪个Client选择的起点。此外,如果您构建 SPA(根据链接中的措辞,即使它是第一方客户端),我更喜欢 Implicit Grant。如果您对特定客户的特定授权有疑问,请在 stackoverflow 上创建一个新问题。

    2. 您可以将IdentityServer3IdentityServer3.EntityFrameworkIdentityServer3.AspNetIdentity 一起使用。您可以将 IdentityServer 表放在现有数据库中,但我不建议将其用于生产。

    【讨论】:

      猜你喜欢
      • 2011-07-21
      • 1970-01-01
      • 2020-10-14
      • 2013-12-31
      • 2021-05-12
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多