如何在成为旧版ASP.NET MVC应用程序的一部分时对Web API 2中的用户进行身份验证?

Chr*_*ian 6 c# authentication asp.net-mvc asp.net-web-api asp.net-web-api2

我有一个Web API,目前AngularJS应用程序在ASP.NET MVC Web应用程序中使用.MVC应用程序使用ASP.NET Forms Authentication作为身份验证机制.当客户端不是Web客户端但是例如独立服务时,我应该如何验证Web API的用户.我现在所做的是为Web API添加一个登录方法,它为任何人提供了正确的凭据访问权限:

[Route("api/v2/login"), HttpPost]
[AllowAnonymous]
public IHttpActionResult Post([FromBody]Credentials credentials)
{
    var principal = FindPrincipal(credentials);
    if (principal != null)
    {
        FormsAuthentication.SetAuthCookie(principal.Identity.Name, false);
        return Ok();
    }
    return Unauthorized();
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果这应该如何解决或者是否有更好的方法?

M. *_*har 3

您可以使用WebApi2的令牌认证机制。

流程将是这样的:

用户向您发送 https 请求:

https://yourApiUrl/令牌

请求的内容类型应该是:

application/x-www-form-urlencoded
Run Code Online (Sandbox Code Playgroud)

正文应包括:

grant_type=password&username=yourWebsFormsUsername&password=yourWebFormsPassword
Run Code Online (Sandbox Code Playgroud)

你的 OWIN 启动类看起来像这样:

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new YourOAuthProvider(),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true,
        };

        app.UseOAuthBearerTokens(OAuthOptions);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意上面的 YourOAuthProvider,这是重要的部分。这是您的自定义提供程序,它将根据您拥有的凭证存储来验证您的用户名/密码。在您的情况下 aspnet_membership 表。此验证在下面的 RequestHasValidCredentials 方法中完成:

public class YourOAuthProvider : OAuthAuthorizationServerProvider
{
    public string apikey = string.Empty;

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        if (RequestHasValidCredentials(context.UserName, context.Password))
        {
            var id = new ClaimsIdentity(context.Options.AuthenticationType);
            id.AddClaim(new Claim("username", context.UserName));

            context.Validated(id);
        }
        else
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }            
    }
}
Run Code Online (Sandbox Code Playgroud)

您的用户对上述内容的响应将是一个令牌,其中包括用户名或您在上述方法中添加到上下文中的任何其他信息:

id.AddClaim(new Claim("username", context.UserName));
Run Code Online (Sandbox Code Playgroud)

上述令牌 api 调用的响应将如下所示:

{
    "access_token": "9TIpW2m2rUbB_Bmb7kKAQ9GH4hgfnKF8g3fL0tAre2gcFjI45fajmG6qdOJe-A",
    "token_type": "bearer",
    "expires_in": 1209599
}
Run Code Online (Sandbox Code Playgroud)

然后,您的用户必须将此令牌作为所有 API 调用的 Http 授权标头传递。他们需要使用承载方案来传递它,例如:

Bearer 9TIpW2m2rUbB_Bmb7kKAQ9GH4hgfnKF8g3fL0tAre2gcFjI45fajmG6qdOJe-A
Run Code Online (Sandbox Code Playgroud)

由于此令牌包含用户名,因此您将能够知道用户是谁。现在最后一件事是读取此令牌并检索用户名。为此,您需要创建一个自定义 Authorize 属性,并用它来装饰您的控制器或方法。

public class YourAuthorizeAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var ticket = Startup.OAuthOptions.AccessTokenFormat.Unprotect(actionContext.Request.Headers.Authorization.Parameter);

        string username = claims.Where(x => x.Type == "username").FirstOrDefault();

        base.OnAuthorization(actionContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

一旦您拥有用户名,所有其他自定义授权逻辑都可以添加到此处。

您可以在生成token时传入其他自定义信息,并在此处读取。(如果您需要任何其他特殊授权逻辑。)

它的方法很冗长,但适用于任何凭据存储。