激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - 詳解ASP.NET Core Token認證

詳解ASP.NET Core Token認證

2020-04-07 12:45indexlang ASP.NET教程

這篇文章主要介紹了詳解ASP.NET Core Token認證,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。

令牌認證(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 認證頭傳遞的,例如:

?
1
2
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中:

?
1
2
3
// 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。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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這個類處理。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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中調用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using Microsoft.IdentityModel.Tokens;
 
namespace SimpleTokenProvider
{
  public class TokenProviderOptions
  {
    public string Path { get; set; } = "/token";
 
    public string Issuer { get; set; }
 
    public string Audience { get; set; }
 
    public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(5);
 
    public SigningCredentials SigningCredentials { get; set; }
  }
}

現在自己添加一個中間件,asp.net core 的中間件類一般是這樣的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
 
namespace SimpleTokenProvider
{
  public class TokenProviderMiddleware
  {
    private readonly RequestDelegate _next;
    private readonly TokenProviderOptions _options;
 
    public TokenProviderMiddleware(
      RequestDelegate next,
      IOptions<TokenProviderOptions> options)
    {
      _next = next;
      _options = options.Value;
    }
 
    public Task Invoke(HttpContext context)
    {
      // If the request path doesn't match, skip
      if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal))
      {
        return _next(context);
      }
 
      // Request must be POST with Content-Type: application/x-www-form-urlencoded
      if (!context.Request.Method.Equals("POST")
        || !context.Request.HasFormContentType)
      {
        context.Response.StatusCode = 400;
        return context.Response.WriteAsync("Bad request.");
      }
 
      return GenerateToken(context);
    }
  }
}

這個中間件類接受TokenProviderOptions作為參數,當有請求且請求路徑是設置的路徑(token或者api/token),Invoke方法執行,token節點只對 POST請求而且包括form-urlencoded內容類型(Content-Type: application/x-www-form-urlencoded),因此調用之前需要檢查下內容類型。

最重要的是GenerateToken,這個方法需要驗證用戶的身份,生成jwt,傳回jwt:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private async Task GenerateToken(HttpContext context)
{
  var username = context.Request.Form["username"];
  var password = context.Request.Form["password"];
 
  var identity = await GetIdentity(username, password);
  if (identity == null)
  {
    context.Response.StatusCode = 400;
    await context.Response.WriteAsync("Invalid username or password.");
    return;
  }
 
  var now = DateTime.UtcNow;
 
  // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
  // You can add other claims here, if you want:
  var claims = new Claim[]
  {
    new Claim(JwtRegisteredClaimNames.Sub, username),
    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    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
  };
 
  // Serialize and return the response
  context.Response.ContentType = "application/json";
  await context.Response.WriteAsync(JsonConvert.SerializeObject(response, new JsonSerializerSettings { Formatting = Formatting.Indented }));
}

大部分代碼都很官方,JwtSecurityToken 類生成jwt,JwtSecurityTokenHandler將jwt編碼,你可以在claims中添加任何chaims。驗證用戶身份只是簡單的驗證,實際情況肯定不是這樣的,你可以集成 identity framework或者其他的,對于這個實例只是簡單的硬編碼:

?
1
2
3
4
5
6
7
8
9
10
11
private Task<ClaimsIdentity> GetIdentity(string username, string password)
{
  // DON'T do this in production, obviously!
  if (username == "TEST" && password == "TEST123")
  {
    return Task.FromResult(new ClaimsIdentity(new System.Security.Principal.GenericIdentity(username, "Token"), new Claim[] { }));
  }
 
  // Credentials are invalid, or account doesn't exist
  return Task.FromResult<ClaimsIdentity>(null);
}

添加一個將DateTime生成timestamp的方法:

?
1
2
public static long ToUnixEpochDate(DateTime date)
  => (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);

現在,你可以將這個中間件添加到startup.cs中了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
 
namespace SimpleTokenProvider
{
  public partial class Startup
  {
    public Startup(IHostingEnvironment env)
    {
      var builder = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", optional: true);
      Configuration = builder.Build();
    }
 
    public IConfigurationRoot Configuration { get; set; }
 
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddMvc();
    }
 
    // The secret key every token will be signed with.
    // In production, you should store this securely in environment variables
    // or a key management tool. Don't hardcode this into your application!
    private static readonly string secretKey = "mysupersecret_secretkey!123";
 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
      loggerFactory.AddConsole(LogLevel.Debug);
      loggerFactory.AddDebug();
 
      app.UseStaticFiles();
 
      // Add JWT generation endpoint:
      var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
      var options = new TokenProviderOptions
      {
        Audience = "ExampleAudience",
        Issuer = "ExampleIssuer",
        SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
      };
 
      app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));
 
      app.UseMvc();
    }
  }
}

測試一下,推薦使用chrome 的postman:

?
1
2
3
POST /token
Content-Type: application/x-www-form-urlencoded
username=TEST&password=TEST123

結果:
OK

Content-Type: application/json
 
{
  "access_token": "eyJhb...",
  "expires_in": 300
}

你可以使用jwt工具查看生成的jwt內容。如果開發的是移動應用或者單頁應用,你可以在后續請求的header中存儲jwt,如果你需要在cookies中存儲的話,你需要對代碼修改一下,需要將返回的jwt字符串添加到cookie中。
測試下:

詳解ASP.NET Core Token認證

詳解ASP.NET Core Token認證

其他方案

下面是比較成熟的項目,可以在實際項目中使用:

  • 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!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/indexlang/p/indexlang.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 少妇一级淫片免费放4p | 曰韩精品| 欧美日韩免费在线观看视频 | 久久久久女人精品毛片九一 | 欧美精品1区 | av播播 | 欧美一区二区网站 | 91成人影院 | 国产成人综合在线 | 日本中文字幕久久 | 欧美色大成网站www永久男同 | 狠狠干天天操 | 可以看逼的视频 | 欧美 日韩 三区 | 国产91免费看 | 精品久久久久久久久久久αⅴ | 中文日韩欧美 | 毛片视频网站 | 精品亚洲视频在线观看 | 国产成年人在线观看 | 99精品视频在线看 | 成人免费观看毛片 | 精品国产一区二区亚洲人成毛片 | 中文字幕亚洲情99在线 | 日韩视频区 | 久久观看 | 久久国产亚洲视频 | 成年片黄色日本大片网站视频 | 国产成人精品区一区二区不卡 | 国产成人精品区 | 日韩在线播放一区二区 | 免费在线观看毛片 | 韩国精品一区二区三区四区五区 | 精品中文一区 | 成人毛片网站 | 国产亚洲自拍一区 | 免费午夜网站 | 一区二区三区无码高清视频 | 中文字幕精品久久 | 久久国产精品久久久久久电车 | 免费香蕉成视频成人网 |