文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

如果你只知道传统的ASP.NET的方法,一个单页应用的认证对你来说是稍微更特别。可以理解为这个app应用是一个完全独立的app应用像一个移动的app有帮助。基于令牌的认证对于这类app应用来说是最好的解决办法。这一次,我将会试着描绘出一高水平的综述并且展示一个简单的解决方法。

简介

正如我上一次写关于angular2和asp.net的核心,我减少asp.net核心http服务,来提供基于json数据给angular2客户端。我的一些读者询问我认证是如何在那种情况写工作的。我不使用任何注册服务器生成的登录页面,注册页面或者类似于这样的。所以asp.net核心部分职能提供web接口和静态文件给客户端。

又很多方法来保护你的应用程序。 最简单的一个方法是使用 Azure Active Directory(用于云的标识和访问管理)。你也可以使用 IdentityServer4来创建一个独立的认证服务器来管理用户,角色以及提供一个基于Token的认证服务。 

关键词: 基于令牌的认证是这种情况下的解决方案。

使用基于Token的认证, 客户端(Web客户端,移动应用程序等)在成功登录后获取基于字符串的加密Token。 令牌还包含一些用户信息和关于令牌将有效多长时间的信息。 该令牌需要存储在客户端,每次请求资源时都需要提交给服务器。 通常,你使用一个HTTP头提交Token。 如果令牌是不再有效,你需要执行一个新的登录。

第 2 段(可获 1.84 积分)

在我们的一个较小的项目中, 没有设置不同的认证服务器,我们没有使用Azure AD 因为我们需要一个快速和廉价的解决方案.。廉价是从客户的角度来看。

Angular2部分

在客户端, 我们使用 angular2-jwt, 这是一个用于处理身份验证的Angular2模块。它检查的有效性, 读取的元信息等等。它提供了一个 Angular2 HTTP服务的包装器。 通过这个包装器,你可以在每一个Http请求的头信息中自动传递Token信息。

第 3 段(可获 1.23 积分)

工作流程是这样的。

  1. 如果Token无效或客户端不存在, 这个用户将会重定向到登录页面。
  2. 用户进入他的凭据,并按下登录按钮。
  3. 这个数据被发送到服务器,一个特殊的中间件将会处理这个请求。
    1. 用户在服务器端得到身份验证。
    2. 这个被创建的Token包含一些验证数据和元数据。
    3. Token返回给客户端。
  4. 客户端将Token存储在本地存储中,cookie 或者其它任何地方,然后再每一个请求中使用。.

angular2-jwt在客户端对我们来说是非常神奇的。 在每次请求给服务器或者每次更新组件的时候我们需要用它来检查可用性。

第 4 段(可获 1.74 积分)

这是一个小例子如何用于Angular2 HTTP包装器:

import { AuthHttp, AuthConfig, AUTH_PROVIDERS } from 'angular2-jwt';

...

class App {

  thing: string;

  constructor(public authHttp: AuthHttp) {}

  getThing() {
    // this uses authHttp, instead of http
    this.authHttp.get('http://example.com/api/thing')
      .subscribe(
        data => this.thing = data,
        err => console.log(err),
        () => console.log('Request Complete')
      );
  }
}

ASP.NET部分

在服务器端, 我们也使用一个单独的开源项目SimpleTokenProvider。这是一个非常简单的用来验证用户的解决方案,通过使用用户的凭证来创建和提供Token。 我不建议使用这种方式在一个大型以及关键的解决方案中。在这种情况下,你应该选择 IdentiyServer或任何其他身份验证,比如Azure AD ,这样更加安全。 该项目的源代码你需要复制到你的项目,然后更改一些行。例如, 用你的数据库或者其他任何形式存储了的用户数据来对用户进行身份认证。这个项目提供了一个中间件,就是在一个定义好的路径上进行监听,比如 /api/tokenauth/。通过客户端的登录界面来给这个URL发送POST请求进行认证。

第 5 段(可获 1.93 积分)

Web Api的认证,只是使用Token,和请求一起发送。 这些已经在IdentiyMiddleware中内置了。 这意味着,如果ASP.NET MVC获得一个携带认证属性的请求给控制器或者Action,它会检查请求的Token。如果Token有效,则对用户进行身份认证。如果用户角色正确,就获得授权。

我们把用户角色信息作为额外的声明信息添加到Token中,这样,信息可以从Token中提取并且在应用程序中使用。

第 6 段(可获 1.24 积分)

查找和识别用户, 我们使用给定的UserManager 和 SignInManager。这些类绑定了IdentityDataContext。当在VisualStudio中创建具有标识的新项目时,这些类已可用.。

这样我们就可以在服务器端对用户进行身份验证:

public async Task<ClaimsIdentity> GetIdentity(string email, string password)
{
    var result = await _signInManager.PasswordSignInAsync(email, password, false, lockoutOnFailure: false);
    if (result.Succeeded)
    {
        var user = await _userManager.FindByEmailAsync(email);
        var claims = await _userManager.GetClaimsAsync(user);

        return new ClaimsIdentity(new GenericIdentity(email, "Token"), claims);
    }

    // Credentials are invalid, or account doesn't exist
    return null;
}

这些声明将被用来进行基于Token的身份认证,在Token认证中间件中:  

var username = context.Request.Form["username"];
var password = context.Request.Form["password"];

var identity = await identityResolver.GetIdentity(username, password);
if (identity == null)
{
    context.Response.StatusCode = 400;
    await context.Response.WriteAsync("Unknown username or password.");
    return;
}

var now = DateTime.UtcNow;

// Specifically add the jti (nonce), iat (issued timestamp), and sub (subject/user) claims.
// You can add other claims here, if you want:
var claims = new[]
{
    new Claim(JwtRegisteredClaimNames.Sub, username),
    new Claim(JwtRegisteredClaimNames.Jti, await _options.NonceGenerator()),
    new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(now).ToString(), ClaimValueTypes.Integer64)
};

// Create the JWT and write it to a string
var jwt = new JwtSecurityToken(
    issuer: _options.Issuer,
    audience: _options.Audience,
    claims: claims,
    notBefore: now,
    expires: now.Add(_options.Expiration),
    signingCredentials: _options.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

var response = new
{
    access_token = encodedJwt,
    expires_in = (int)_options.Expiration.TotalSeconds,
    admin = identity.IsAdministrator(),
    fullname = identity.FullName(),
    username = identity.Name
};

// Serialize and return the response
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(response, _serializerSettings)
第 7 段(可获 0.81 积分)

结论

这只是一个小概述。如果你想了解跟多关于ASP.NET的身份认证的原理信息,你一定要订阅Dominick Baier 和Brock Allen的博客。即使是 ASP.NET 文档也是去 学习更多关于 ASP.NET安全非常好的资源。

更新: 就在最近, Scott Brady 写了一篇关于 开始使用 IdentityServer 4的博客。

第 8 段(可获 0.83 积分)

文章评论