ASP.NET Core系列:JWT身份認證

1. JWT概述

  JSON Web Token(JWT)是目前流行的跨域身份驗證解決方案。算法

  JWT的官網地址:https://jwt.iojson

  JWT的實現方式是將用戶信息存儲在客戶端,服務端不進行保存。每次請求都把令牌帶上以校驗用戶登陸狀態,這樣服務就變成無狀態的,利於服務器集羣擴展。api

1.1 JWT令牌結構

  在緊湊的形式中,JSON Web Tokens由dot(.)分隔的三個部分組成:跨域

  ◊ Header 頭安全

  ◊ Payload 載荷服務器

  ◊ Signature 簽名app

  所以,JWT一般如右所示:xxxxx.yyyyy.zzzzzui

  (1)Header編碼

  標頭一般由兩部分組成:令牌的類型,即JWT,以及正在使用的簽名算法,如:HMAC SHA256或RSA。加密

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

  而後,這個JSON被編碼爲Base64Url,造成JWT的第一部分。

  (2)Payload

  Payload用來存放須要傳遞的數據,包括用戶信息及認證信息等。

  JWT 規定了7個官方字段,供選用。

  ◊ iss (issuer):簽發人

  ◊ exp (expiration time):過時時間

  ◊ sub (subject):主題

  ◊ aud (audience):受衆

  ◊ nbf (Not Before):生效時間

  ◊ iat (Issued At):簽發時間

  ◊ jti (JWT ID):編號

  除了官方字段,能夠在這個部分自定義其它字段。

  而後,這個JSON被編碼爲Base64Url,造成JWT的第二部分。

  注意:JWT 默認是不加密的,任何人均可以讀到,因此不要把祕密信息放在這個部分。

  (3)Signature

  Signature 部分是對前兩部分的簽名,防止數據篡改。這部分存在的意義就是爲了解決前面部分的不安全性。

  首先,須要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。而後,使用 Header 裏面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。

HMACSHA256( 
  base64UrlEncode(header) + "." + 
  base64UrlEncode(payload), 
  SECREATE_KEY 
)

  簽名用於驗證消息在此過程當中未被更改,而且,在使用私鑰簽名的令牌的狀況下,它還能夠驗證JWT的發件人是不是它所聲稱的人。

2. ASP.NET Core中集成JWT身份認證

  新建ASP.NET Core API應用程序,添加安裝包:

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package System.IdentityModel.Tokens.Jwt

  appsettings.json

{
  "Jwt": {
    "Issuer": "Issuer",
    "Audience": "Audience",
    "SigningKey": "EF1DA5B7-C4FA-4240-B997-7D1701BF9BE2"
  }
}

  JwtConfig.cs

public class JwtConfig
{
    public string Issuer { get; set; }

    public string Audience { get; set; }

    public string SigningKey { get; set; }
}

  Startup.cs

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        var jwtconfig = Configuration.GetSection("Jwt").Get<JwtConfig>();
        // JWT身份認證
        services.AddAuthentication(option =>
        {
            option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(option =>
        {
            option.TokenValidationParameters = new TokenValidationParameters
            {
                ValidIssuer = jwtconfig.Issuer,
                ValidAudience = jwtconfig.Audience,
                ValidateIssuer = true,
                ValidateLifetime = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtconfig.SigningKey)),
                // 緩衝過時時間,總的有效時間等於這個時間加上jwt的過時時間,若是不配置,默認是5分鐘
                ClockSkew = TimeSpan.FromSeconds(3)
            };
        });

        services.AddOptions().Configure<JwtConfig>(Configuration.GetSection("Jwt"));

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // JWT身份認證
        app.UseAuthentication();

        app.UseMvc();
    }
}

  AuthController.cs

using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;

[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    private JwtConfig jwtconfig;
    public AuthController(IOptions<JwtConfig> option)
    {
        jwtconfig = option.Value;
    }

    [HttpGet]
    public ActionResult<string> Get()
    {
        var claim = new Claim[]{
            new Claim("UserName", "lb")
        };
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtconfig.SigningKey));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var token = new JwtSecurityToken(
            issuer: jwtconfig.Issuer,
            audience: jwtconfig.Audience,
            claims: claim,
            notBefore: DateTime.Now,
            expires: DateTime.Now.AddSeconds(30),
            signingCredentials: creds);

        return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
    }

    /// <summary>
    /// 在須要身份認證的方法添加[Authorize]
    /// </summary>
    [Authorize]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return "value";
    }
}

  在訪問須要JWT身份認證的接口時,接口添加header參數Authorization,值爲「Bearer」+空格+token。若不能經過JWT身份認證,則調用接口返回狀態401未認證。

相關文章
相關標籤/搜索