JwtBearer認證

ASP.NET Core 認證與受權[4]:JwtBearer認證

 

在現代Web應用程序中,一般會使用Web, WebApp, NativeApp等多種呈現方式,然後端也由之前的Razor渲染HTML,轉變爲Stateless的RESTFulAPI,所以,咱們須要一種標準的,通用的,無狀態的,與語言無關的認證方式,也就是本文要介紹的JwtBearer認證。html

目錄前端

  1. Bearer認證
  2. JWT(JSON WEB TOKEN)
  3. 示例
  4. 擴展
  5. 源碼探索

Bearer認證

HTTP提供了一套標準的身份驗證框架:服務器能夠用來針對客戶端的請求發送質詢(challenge),客戶端根據質詢提供身份驗證憑證。質詢與應答的工做流程以下:服務器端向客戶端返回401(Unauthorized,未受權)狀態碼,並在WWW-Authenticate頭中添加如何進行驗證的信息,其中至少包含有一種質詢方式。而後客戶端能夠在請求中添加Authorization頭進行驗證,其Value爲身份驗證的憑證信息。git

HTTPAuth

在HTTP標準驗證方案中,咱們比較熟悉的是"Basic"和"Digest",前者將用戶名密碼使用BASE64編碼後做爲驗證憑證,後者是Basic的升級版,更加安全,由於Basic是明文傳輸密碼信息,而Digest是加密後傳輸。在前文介紹的Cookie認證屬於Form認證,並不屬於HTTP標準驗證。github

本文要介紹的Bearer驗證也屬於HTTP協議標準驗證,它隨着OAuth協議而開始流行,詳細定義見: RFC 6570web

A security token with the property that any party in possession of the token (a "bearer") can use the token in any way that any other party in possession of it can. Using a bearer token does not require a bearer to prove possession of cryptographic key material (proof-of-possession).算法

Bearer驗證中的憑證稱爲BEARER_TOKEN,或者是access_token,它的頒發和驗證徹底由咱們本身的應用程序來控制,而不依賴於系統和Web服務器,Bearer驗證的標準請求方式以下:json

Authorization: Bearer [BEARER_TOKEN]

那麼使用Bearer驗證有什麼好處呢?後端

  • CORS: cookies + CORS 並不能跨不一樣的域名。而Bearer驗證在任何域名下均可以使用HTTP header頭部來傳輸用戶信息。api

  • 對移動端友好: 當你在一個原平生臺(iOS, Android, WindowsPhone等)時,使用Cookie驗證並非一個好主意,由於你得和Cookie容器打交道,而使用Bearer驗證則簡單的多。瀏覽器

  • CSRF: 由於Bearer驗證再也不依賴於cookies, 也就避免了跨站請求攻擊。

  • 標準:在Cookie認證中,用戶未登陸時,返回一個302到登陸頁面,這在非瀏覽器狀況下很難處理,而Bearer驗證則返回的是標準的401 challenge

JWT(JSON WEB TOKEN)

上面介紹的Bearer認證,其核心即是BEARER_TOKEN,而最流行的Token編碼方式即是:JSON WEB TOKEN。

Json web token (JWT), 是爲了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標準(RFC 7519)。該token被設計爲緊湊且安全的,特別適用於分佈式站點的單點登陸(SSO)場景。JWT的聲明通常被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源,也能夠增長一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。

JWT是由.分割的以下三部分組成:

頭部(Header)

Header 通常由兩個部分組成:

  • alg
  • typ

alg是是所使用的hash算法,如:HMAC SHA256或RSA,typ是Token的類型,在這裏就是:JWT

{ "alg": "HS256", "typ": "JWT" }

而後使用Base64Url編碼成第一部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<second part>.<third part>

載荷(Payload)

這一部分是JWT主要的信息存儲部分,其中包含了許多種的聲明(claims)。

Claims的實體通常包含用戶和一些元數據,這些claims分紅三種類型:

  • reserved claims:預約義的 一些聲明,並非強制的可是推薦,它們包括 iss (issuer), exp (expiration time), sub (subject),aud(audience) 等(這裏都使用三個字母的緣由是保證 JWT 的緊湊)。

  • public claims: 公有聲明,這個部分能夠隨便定義,可是要注意和 IANA JSON Web Token 衝突。

  • private claims: 私有聲明,這個部分是共享被認定信息中自定義部分。

一個簡單的Pyload能夠是這樣子的:

{ "sub": "1234567890", "name": "John Doe", "admin": true }

這部分一樣使用Base64Url編碼成第二部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.<third part>

簽名(Signature)

Signature是用來驗證發送者的JWT的同時也能確保在期間不被篡改。

在建立該部分時候你應該已經有了編碼後的Header和Payload,而後使用保存在服務端的祕鑰對其簽名,一個完整的JWT以下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

所以使用JWT具備以下好處:

  • 通用:由於json的通用性,因此JWT是能夠進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等不少語言均可以使用。

  • 緊湊:JWT的構成很是簡單,字節佔用很小,能夠經過 GET、POST 等放在 HTTP 的 header 中,很是便於傳輸。

  • 擴展:JWT是自我包涵的,包含了必要的全部信息,不須要在服務端保存會話信息, 很是易於應用的擴展。

關於更多JWT的介紹,網上很是多,這裏就再也不多作介紹。下面,演示一下 ASP.NET Core 中 JwtBearer 認證的使用方式。

示例

模擬Token

ASP.NET Core 內置的JwtBearer驗證,並不包含Token的發放,咱們先模擬一個簡單的實現:

[HttpPost("authenticate")] public IActionResult Authenticate([FromBody]UserDto userDto) { var user = _store.FindUser(userDto.UserName, userDto.Password); if (user == null) return Unauthorized(); var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(Consts.Secret); var authTime = DateTime.UtcNow; var expiresAt = authTime.AddDays(7); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(JwtClaimTypes.Audience,"api"), new Claim(JwtClaimTypes.Issuer,"http://localhost:5200"), new Claim(JwtClaimTypes.Id, user.Id.ToString()), new Claim(JwtClaimTypes.Name, user.Name), new Claim(JwtClaimTypes.Email, user.Email), new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber) }), Expires = expiresAt, SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); var tokenString = tokenHandler.WriteToken(token); return Ok(new { access_token = tokenString, token_type = "Bearer", profile = new { sid = user.Id, name = user.Name, auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds(), expires_at = new DateTimeOffset(expiresAt).ToUnixTimeSeconds() } }); }

如上,使用微軟提供的Microsoft.IdentityModel.Tokens幫助類(源碼地址:azure-activedirectory-identitymodel-extensions-for-dotnet),能夠很容易的建立出JwtToen,就再也不多說。

註冊JwtBearer認證

首先添加JwtBearer包引用:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 2.0.0

而後在Startup類中添加以下配置:

public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.TokenValidationParameters = new TokenValidationParameters { NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role, ValidIssuer = "http://localhost:5200", ValidAudience = "api", IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Consts.Secret)) /***********************************TokenValidationParameters的參數默認值***********************************/ // RequireSignedTokens = true, // SaveSigninToken = false, // ValidateActor = false, // 將下面兩個參數設置爲false,能夠不驗證Issuer和Audience,可是不建議這樣作。 // ValidateAudience = true, // ValidateIssuer = true, // ValidateIssuerSigningKey = false, // 是否要求Token的Claims中必須包含Expires // RequireExpirationTime = true, // 容許的服務器時間偏移量 // ClockSkew = TimeSpan.FromSeconds(300), // 是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比 // ValidateLifetime = true }; }); } public void Configure(IApplicationBuilder app) { app.UseAuthentication(); }

JwtBearerOptions的配置中,一般IssuerSigningKey(簽名祕鑰)ValidIssuer(Token頒發機構)ValidAudience(頒發給誰) 三個參數是必須的,後二者用於與TokenClaims中的IssuerAudience進行對比,不一致則驗證失敗(與上面發放Token中的Claims對應)。

NameClaimTypeRoleClaimType需與Token中的ClaimType一致,在IdentityServer中也是使用的JwtClaimTypes,不然會形成User.Identity.Name爲空等問題。

添加受保護資源

建立一個須要受權的控制器,直接使用Authorize便可:

[Authorize]
[Route("api/[controller]")] public class SampleDataController : Controller { [HttpGet("[action]")] public IEnumerable<WeatherForecast> WeatherForecasts() { return ... } }

運行

最後運行,直接訪問/api/SampleData/WeatherForecasts,將返回一個401:

HTTP/1.1 401 Unauthorized
Server: Kestrel
Content-Length: 0
WWW-Authenticate: Bearer

讓咱們調用api/oauth/authenticate,獲取一個JWT:

請求:
POST http://localhost:5200/api/oauth/authenticate HTTP/1.1
content-type: application/json

{
  "username": "alice",
  "password": "alice"
}

響應:
HTTP/1.1 200 OK
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJuYW1lIjoiYWxpY2UiLCJlbWFpbCI6ImFsaWNlQGdtYWlsLmNvbSIsInBob25lX251bWJlciI6IjE4ODAwMDAwMDAxIiwibmJmIjoxNTA5NDY0MzQwLCJleHAiOjE1MTAwNjkxNDAsImlhdCI6MTUwOTQ2NDM0MH0.Y1TDz8KjLRh_vjQ_3iYP4oJw-fmhoboiAGPqIZ-ooNc","token_type":"Bearer","profile":{"sid":1,"name":"alice","auth_time":1509464340,"expires_at":1510069140}}

最後使用該Token,再次調用受保護資源:

GET http://localhost:5200/api/SampleData/WeatherForecasts HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJuYW1lIjoiYWxpY2UiLCJlbWFpbCI6ImFsaWNlQGdtYWlsLmNvbSIsInBob25lX251bWJlciI6IjE4ODAwMDAwMDAxIiwibmJmIjoxNTA5NDY0MzQwLCJleHAiOjE1MTAwNjkxNDAsImlhdCI6MTUwOTQ2NDM0MH0.Y1TDz8KjLRh_vjQ_3iYP4oJw-fmhoboiAGPqIZ-ooNc

受權成功,返回了預期的數據:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[{"dateFormatted":"2017/11/3","temperatureC":35,"summary":"Chilly","temperatureF":94}]

擴展

自定義Token獲取方式

JwtBearer認證中,默認是經過Http的Authorization頭來獲取的,這也是最推薦的作法,可是在某些場景下,咱們可能會使用Url或者是Cookie來傳遞Token,那要怎麼來實現呢?

其實實現起來很是簡單,如前幾章介紹的同樣,JwtBearer也在認證的各個階段爲咱們提供了事件,來執行咱們的自定義邏輯:

.AddJwtBearer(o =>
{
    o.Events = new JwtBearerEvents() { OnMessageReceived = context => { context.Token = context.Request.Query["access_token"]; return Task.CompletedTask; } }; o.TokenValidationParameters = new TokenValidationParameters { ... };

而後在Url中添加access_token=[token],直接在瀏覽器中訪問:

access_token_in_url

一樣的,咱們也能夠很容易的在Cookie中讀取Token,就再也不演示。

除了OnMessageReceived外,還提供了以下幾個事件:

  • TokenValidated:在Token驗證經過後調用。

  • AuthenticationFailed: 認證失敗時調用。

  • Challenge: 未受權時調用。

使用OIDC服務

在上面的示例中,咱們簡單模擬的Token頒發,功能很是簡單,並不適合在生產環境中使用,但是微軟也沒有提供OIDC服務的實現,好在.NET社區中提供了幾種實現,可供咱們選擇:

Name Description
AspNet.Security.OpenIdConnect.Server (ASOS) Low-level/protocol-first OpenID Connect server framework for ASP.NET Core and OWIN/Katana
IdentityServer4 OpenID Connect and OAuth 2.0 framework for ASP.NET Core - officially certified by the OpenID Foundation and under governance of the .NET Foundation
OpenIddict Easy-to-use OpenID Connect server for ASP.NET Core
PwdLess Simple, stateless, passwordless authentication for ASP.NET Core

咱們在這裏使用IdentityServer4來搭建一個OIDC服務器,並添加以下配置:

/********************OIDC服務器代碼片斷********************/ public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // 配置IdentitryServer services.AddIdentityServer() .AddInMemoryPersistedGrants() .AddInMemoryApiResources(Config.GetApis()) .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers()) .AddDeveloperSigningCredential(); } new Client { ClientId = "jwt.implicit", ClientName = "Implicit Client (Web)", AllowedGrantTypes = GrantTypes.Implicit, AllowAccessTokensViaBrowser = true, RedirectUris = { "http://localhost:5200/callback" }, PostLogoutRedirectUris = { "http://localhost:5200/home" }, AllowedCorsOrigins = { "http://localhost:5200" }, AllowedScopes = { "openid", "profile", "email", "api" }, }

而JwtBearer客戶端的配置就更加簡單了,由於OIDC具備配置發現的功能:

public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.Authority = "https://oidc.faasx.com/"; o.Audience = "api"; o.TokenValidationParameters = new TokenValidationParameters { NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role, }; }); }

如上,最重要的是Authority參數,用來表示OIDC服務的地址,而後即可以自動發現IssuerIssuerSigningKey等配置,而o.Audienceo.TokenValidationParameters = new TokenValidationParameters { ValidAudience = "api" }是等效的,後面分析源碼時會介紹。

OIDC兼容OAuth2協議,咱們可使用上一章介紹的受權碼模式來獲取Token,也能夠直接用戶名密碼模式來獲取Token:

請求:
POST https://oidc.faasx.com/connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

client_id=client.rop&client_secret=secret&grant_type=password&scope=api&username=alice&password=alice

響應:
HTTP/1.1 200 OK
Content-Type: application/json

{"access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjdlYzk5MjVlMmUzMTA2NmY2ZmU2ODgzMDRhZjU1ZmM0IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDk2NzI1NjksImV4cCI6MTUwOTY3NjE2OSwiaXNzIjoiaHR0cHM6Ly9vaWRjLmZhYXN4LmNvbSIsImF1ZCI6WyJodHRwczovL29pZGMuZmFhc3guY29tL3Jlc291cmNlcyIsImFwaSJdLCJjbGllbnRfaWQiOiJjbGllbnQucm9wIiwic3ViIjoiMDAxIiwiYXV0aF90aW1lIjoxNTA5NjcyNTY5LCJpZHAiOiJsb2NhbCIsIm5hbWUiOiJBbGljZSBTbWl0aCIsImVtYWlsIjoiQWxpY2VTbWl0aEBlbWFpbC5jb20iLCJzY29wZSI6WyJhcGkiXSwiYW1yIjpbInB3ZCJdfQ.PM93LThOZA3lkgPFVwieqGQQQtgmYDCY0oSFVmudv1hpKO6UaaZsmnn4ci9QjbGl5g2433JkDks5UIZsZ0xE62Qqq8PicPBBuaNoYrCf6dxR7j-0uZcoa7-FCKGu-0TrM8OL-NuMvN6_KEpbWa3jlkwibCK9YDIwJZilVoWUOrbbIEsKTa-DdLScmzHLUzksT8GBr0PAVhge9PRFiGqg8cgMLjsA62ZeDsR35f55BucSV5Pj0SAj26anYvrBNTHKOF7ze1DGW51Dbz6DRu1X7uEIxSzWiNi4cRVJ6Totjkwk5F78R9R38o_mYEdehZBjRHFe6zLd91hXcCKqOEh5eQ","expires_in":3600,"token_type":"Bearer"}

咱們使用https://jwt.io解析一下OIDC服務器頒發的Token中的Claims:

{ "nbf": 1509672569, // 2017/11/3 1:29:29 NotBefore Token生效時間,在此以前不可用 "exp": 1509676169, // 2017/11/3 2:29:29 Expiration Token過時時間,在此以後不可用 "iss": "https://oidc.faasx.com", // Issuer 頒發者,一般爲STS服務器地址 "aud": [ // Audience Token的做用對象,也就是被訪問的資源服務器受權標識 "https://oidc.faasx.com/resources", "api" ], "client_id": "client.rop", // 客戶端標識 "sub": "001", "auth_time": 1509672569, // Token頒發時間 "idp": "local", "name": "Alice Smith", "email": "AliceSmith@email.com", "scope": [ "api" ], "amr": [ "pwd" ] }

我在本章的示例代碼中,使用前端Angular框架演示瞭如何從本地登陸獲取Tokek或使用簡化模式(implicit)從OIDC服務器獲取Token,而後保存到sesstionStorage,在發送請求時附加到請求頭中的示例,可供你們參考:JwtBearerSample

源碼探索

JwtBearerPostConfigureOptions

在ASP.NET Core 2.0 Options框架中,新增了一種PostConfigure模式,用來在咱們所註冊的Options配置執行完以後,再對Options作一些修改。

JwtBearerPostConfigureOptions用來實現配置發現:

public class JwtBearerPostConfigureOptions : IPostConfigureOptions<JwtBearerOptions> { public void PostConfigure(string name, JwtBearerOptions options) { // 若是未設置options.TokenValidationParameters.ValidAudience,則使用options.Audience if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(options.Audience)) { options.TokenValidationParameters.ValidAudience = options.Audience; } if (options.ConfigurationManager == null) { // 若是未設置MetadataAddress,則使用options.Authority+.well-known/openid-configuration .... options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(options.MetadataAddress, new OpenIdConnectConfigurationRetriever(), new HttpDocumentRetriever(httpClient) { RequireHttps = options.RequireHttpsMetadata }); } } } }

JwtBearerHandler

JwtBearerHandler相對於前幾章介紹的CookieHandler, OpenIdConnectHandler等,都簡單的多。

首先即是從請求中獲取Token:

protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options); // 先觸發MessageReceived事件,來獲取Token await Events.MessageReceived(messageReceivedContext); if (messageReceivedContext.Result != null) { return messageReceivedContext.Result; } token = messageReceivedContext.Token; // Token爲空時,從Authorization頭中獲取 if (string.IsNullOrEmpty(token)) { string authorization = Request.Headers["Authorization"]; if (string.IsNullOrEmpty(authorization)) { return AuthenticateResult.NoResult(); } if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { token = authorization.Substring("Bearer ".Length).Trim(); } if (string.IsNullOrEmpty(token)) { return AuthenticateResult.NoResult(); } } ... }

而後初始化TokenValidationParameters參數,爲Token驗證作準備:

if (_configuration == null && Options.ConfigurationManager != null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); } var validationParameters = Options.TokenValidationParameters.Clone(); if (_configuration != null) { var issuers = new[] { _configuration.Issuer }; validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuers) ?? issuers; validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys) ?? _configuration.SigningKeys; }

能夠看到,從OIDC服務器提供的配置發現中,獲取ValidIssuersIssuerSigningKeys

最後對Token進行驗證:

// Options.SecurityTokenValidators 默認爲: new List<ISecurityTokenValidator> { new JwtSecurityTokenHandler() } foreach (var validator in Options.SecurityTokenValidators) { if (validator.CanReadToken(token)) { ClaimsPrincipal principal; try { principal = validator.ValidateToken(token, validationParameters, out validatedToken); } catch (Exception ex) { // RefreshOnIssuerKeyNotFound默認爲True, 在SignatureKey未找到時,從新從OIDC服務器獲取 if (Options.RefreshOnIssuerKeyNotFound && Options.ConfigurationManager != null && ex is SecurityTokenSignatureKeyNotFoundException) { Options.ConfigurationManager.RequestRefresh(); } continue; } ... // 觸發TokenValidated事件 await Events.TokenValidated(tokenValidatedContext); // 默認爲true,保存Token到`AuthenticationProperties`中,能夠經過`context.AuthenticateAsync()`來獲取,在咱們須要在服務端使用用戶Token調用其餘資源是很是有用。 if (Options.SaveToken) { tokenValidatedContext.Properties.StoreTokens(new[] { new AuthenticationToken { Name = "access_token", Value = token } }); } // 驗證成功 tokenValidatedContext.Success(); return tokenValidatedContext.Result; } }

其核心的驗證也是在Microsoft.IdentityModel.Tokens中,就不在深究。

當使用JwtBearer認證時,咱們確定不但願在未登陸時返回一個302,所以在前面的示例中,咱們配置了x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;,對應的,會執行JwtBearerHandler的HandleChallengeAsync方法:

protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { var authResult = await HandleAuthenticateOnceSafeAsync(); var eventContext = new JwtBearerChallengeContext(Context, Scheme, Options, properties) { AuthenticateFailure = authResult?.Failure }; if (Options.IncludeErrorDetails && eventContext.AuthenticateFailure != null) { eventContext.Error = "invalid_token"; eventContext.ErrorDescription = CreateErrorDescription(eventContext.AuthenticateFailure); } await Events.Challenge(eventContext); if (eventContext.Handled) { return; } Response.StatusCode = 401; // 最終將相應報文拼接成以下: // https://tools.ietf.org/html/rfc6750#section-3.1 // WWW-Authenticate: Bearer realm="example", error="invalid_token", error_description="The access token expired" }

ASP.NET Core JwtBearer認證的完整源碼地址:Microsoft.AspNetCore.Authentication.JwtBearer

總結

JwtToken其實與Cookie認證中加密後的Cookie值很像,他們都是基於Claim的,認證時無需STS(Security token service)的參與,這在分佈式環境下提供了極大的便利。而他們的本質上的區別是:Cookie是微軟式的,很難與其餘語言集成,而JwtToken則是開放再開放,與平臺,語言無關,在前端也能夠直接解析出Claims。

PS: 在使用在Bearer認證時,一般還需與刷新Token配合來使用,由於JwtToken的驗證是無需通過STS的,而當用戶執行了退出,修改密碼等操做時,是沒法使該Token失效的。因此,一般會給access_token設置一個較短的有效期(JwtBearer認證默認會驗證有效期,經過notBeforeexpires來驗證),當access_token過時後,能夠在用戶無感知的狀況下,使用refresh_token自動從STS從新獲取access_token,但這就不屬於Bearer認證的範疇了,在後續介紹IdentityServer時再來詳細介紹一下。

 
分類:  .NET Core, ASP.NET Core
相關文章
相關標籤/搜索