JSON Web Token(JWT)是目前流行的跨域身份驗證解決方案。算法
JWT的官網地址:https://jwt.iojson
JWT的實現方式是將用戶信息存儲在客戶端,服務端不進行保存。每次請求都把令牌帶上以校驗用戶登陸狀態,這樣服務就變成無狀態的,利於服務器集羣擴展。api
在緊湊的形式中,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的發件人是不是它所聲稱的人。
新建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未認證。