您的位置:首页 > 编程语言 > ASP

ASP.NET Core Token认证

2016-07-14 17:47 555 查看

翻译:Token Authentication in ASP.NET Core

令牌认证(Token Authentication)已经成为单页应用(SPA)和移动应用事实上的标准。即使是传统的B/S应用也能利用其优点。优点很明白:极少的服务端数据管理、可扩展性、可以使用单独的认证服务器和应用服务器分离。

如果你对令牌(token)不是太了解,可以看这篇文章( overview of token authentication and JWTs

令牌认证在asp.net core中集成。其中包括保护Bearer Jwt的路由功能,但是移除了生成token和验证token的部分,这些可以自定义或者使用第三方库来实现,得益于此,MVC和Web api项目可以使用令牌认证,而且很简单。下面将一步一步实现,代码可以在( 源码)下载。

ASP.NET Core令牌验证

首先,背景知识:认证令牌,例如JWTs,是通过http 认证头传递的,例如:

GET /foo
Authorization: Bearer [token]


令牌可以通过浏览器cookies。传递方式是header或者cookies取决于应用和实际情况,对于移动app,使用headers,对于web,推荐在html5 storage中使用cookies,来防止xss攻击。

asp.net core对jwts令牌的验证很简单,特别是你通过header传递。

1、生成 SecurityKey,这个例子,我生成对称密钥验证jwts通过HMAC-SHA256加密方式,在startup.cs中:

// secretKey contains a secret passphrase only your server knows
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));


验证 header中传递的JWTs

Startup.cs
中,使用Microsoft.AspNetCore.Authentication.JwtBearer中的
UseJwtBearerAuthentication
方法获取受保护的api或者mvc路由有效的jwt。

var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,

// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = "ExampleIssuer",

// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = "ExampleAudience",

// Validate the token expiry
ValidateLifetime = true,

// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters
});


通过这个中间件,任何[Authorize]的请求都需要有效的jwt:

签名有效;

过期时间;

有效时间;

Issuer 声明等于“ExampleIssuer”

订阅者声明等于 “ExampleAudience”

如果不是合法的JWT,请求终止,issuer声明和订阅者声明不是必须的,它们用来标识应用和客户端。

在cookies中验证JWTs

ASP.NET Core中的cookies 认证不支持传递jwt。需要自定义实现 ISecureDataFormat接口的类。现在,你只是验证token,不是生成它们,只需要实现
Unprotect
方法,其他的交给System.IdentityModel.Tokens.Jwt.
JwtSecurityTokenHandler这个类处理。


using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.IdentityModel.Tokens;

namespace SimpleTokenProvider
{
public class CustomJwtDataFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string algorithm;
private readonly TokenValidationParameters validationParameters;

public CustomJwtDataFormat(string algorithm, TokenValidationParameters validationParameters)
{
this.algorithm = algorithm;
this.validationParameters = validationParameters;
}

public AuthenticationTicket Unprotect(string protectedText)
=> Unprotect(protectedText, null);

public AuthenticationTicket Unprotect(string protectedText, string purpose)
{
var handler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = null;
SecurityToken validToken = null;

try
{
principal = handler.ValidateToken(protectedText, this.validationParameters, out validToken);

var validJwt = validToken as JwtSecurityToken;

if (validJwt == null)
{
throw new ArgumentException("Invalid JWT");
}

if (!validJwt.Header.Alg.Equals(algorithm, StringComparison.Ordinal))
{
throw new ArgumentException($"Algorithm must be '{algorithm}'");
}

// Additional custom validation of JWT claims here (if any)
}
catch (SecurityTokenValidationException)
{
return null;
}
catch (ArgumentException)
{
return null;
}

// Validation passed. Return a valid AuthenticationTicket:
return new AuthenticationTicket(principal, new AuthenticationProperties(), "Cookie");
}

// This ISecureDataFormat implementation is decode-only
public string Protect(AuthenticationTicket data)
{
throw new NotImplementedException();
}

public string Protect(AuthenticationTicket data, string purpose)
{
throw new NotImplementedException();
}
}
}


在startup.cs中调用

var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,

// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = "ExampleIssuer",

// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = "ExampleAudience",

// Validate the token expiry
ValidateLifetime = true,

// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
AuthenticationScheme = "Cookie",
CookieName = "access_token",
TicketDataFormat = new CustomJwtDataFormat(
SecurityAlgorithms.HmacSha256,
tokenValidationParameters)
});


如果请求中包含名为access_token的cookie验证为合法的JWT,这个请求就能返回正确的结果,如果需要,你可以加上额外的jwt chaims,或者复制jwt chaims到ClaimsPrincipal在
CustomJwtDataFormat.Unprotect方法中,上面是验证token,下面将在asp.net core中生成token。


ASP.NET Core生成Tokens

在asp.net 4.5中,这个UseOAuthAuthorizationServer中间件可以轻松的生成tokens,但是在asp.net core取消了,下面写一个简单的token生成中间件,最后,有几个现成解决方案的链接,供你选择。

简单的token生成节点

首先,生成 POCO保存中间件的选项. 生成类:
TokenProviderOptions.cs


200 OK
Content-Type: application/json

{
"access_token": "eyJhb...",
"expires_in": 300
}


View Code
你可以使用jwt工具查看生成的jwt内容。如果开发的是移动应用或者单页应用,你可以在后续请求的header中存储jwt,如果你需要在cookies中存储的话,你需要对代码修改一下,需要将返回的jwt字符串添加到cookie中。

测试下:




其他方案

下面是比较成熟的项目,可以在实际项目中使用:

AspNet.Security.OpenIdConnect.Server – ASP.NET 4.x的验证中间件。

OpenIddict – 在identity上添加OpenId验证。

IdentityServer4 – .NET Core认证中间件(现在测试版本)。

下面的文章可以让你更加的了解认证:

Overview of Token Authentication Features

How Token Authentication Works in Stormpath

Use JWTs the Right Way!

谢谢阅读,第一次翻译。。。。。。。。

请多多指正。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: