JWT基础

  1. 安装NuGet包Microsoft.AspNetCore.Authentication.JwtBearer
  2. 引入JWTHelper
    using Microsoft.Extensions.Configuration;
    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.Text;
    using System.IdentityModel.Tokens.Jwt;
    
    namespace JwtAuthDemo.Helpers
    {
        public class JwtHelpers
        {
            private readonly IConfiguration Configuration;
    
            public JwtHelpers(IConfiguration configuration)
            {
                this.Configuration = configuration;
            }
            public string GenerateToken(string userName, int expireMinutes = 30)
            {
                var issuer = Configuration.GetValue<string>("JwtSettings:Issuer");
                var signKey = Configuration.GetValue<string>("JwtSettings:SignKey");
    
                // 設定要加入到 JWT Token 中的聲明資訊(Claims)
                var claims = new List<Claim>();
    
                // 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims,我們應該只用的到兩種!
                //claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer));
                claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userName)); // User.Identity.Name
                //claims.Add(new Claim(JwtRegisteredClaimNames.Aud, "The Audience"));
                //claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddMinutes(30).ToUnixTimeSeconds().ToString()));
                //claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須為數字
                //claims.Add(new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須為數字
                claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); // JWT ID
    
                // 網路上常看到的這個 NameId 設定是多餘的
                //claims.Add(new Claim(JwtRegisteredClaimNames.NameId, userName));
    
                // 這個 Claim 也以直接被 JwtRegisteredClaimNames.Sub 取代,所以也是多餘的
                //claims.Add(new Claim(ClaimTypes.Name, userName));
    
                // 你可以自行擴充 "roles" 加入登入者該有的角色
                claims.Add(new Claim("roles", "Admin"));
                claims.Add(new Claim("roles", "Users"));
    
                var userClaimsIdentity = new ClaimsIdentity(claims);
    
                // 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用
                var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signKey));
    
                // HmacSha256 有要求必須要大於 128 bits,所以 key 不能太短,至少要 16 字元以上
                // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
                var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
    
                // 建立 SecurityTokenDescriptor
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Issuer = issuer,
                    //Audience = issuer, // 由於你的 API 受眾通常沒有區分特別對象,因此通常不太需要設定,也不太需要驗證
                    //NotBefore = DateTime.Now, // 預設值就是 DateTime.Now
                    //IssuedAt = DateTime.Now, // 預設值就是 DateTime.Now
                    Subject = userClaimsIdentity,
                    Expires = DateTime.Now.AddMinutes(expireMinutes),
                    SigningCredentials = signingCredentials
                };
    
                // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
                var tokenHandler = new JwtSecurityTokenHandler();
                var securityToken = tokenHandler.CreateToken(tokenDescriptor);
                var serializeToken = tokenHandler.WriteToken(securityToken);
    
                return serializeToken;
            }
        }
    }

     

  3. 添加
  4. 加入验证,注入等
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using Microsoft.OpenApi.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using JwtAuthDemo.Helpers;
    using Microsoft.IdentityModel.Tokens;
    using System.Text;
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    
    namespace WebApplication1
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
    
                services.AddControllers();
                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" });
                    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                    {
    
                        Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
                        Name = "Authorization",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.ApiKey,
                        BearerFormat = "JWT",
                        Scheme = "Bearer"
                    });
    
                    c.AddSecurityRequirement(new OpenApiSecurityRequirement
                    {
                        {
                            new OpenApiSecurityScheme
                            {
                                Reference = new OpenApiReference {
                                    Type = ReferenceType.SecurityScheme,
                                    Id = "Bearer"
                                }
                            },
                            new string[] { }
                        }
                    });
                });
                services.AddSingleton<JwtHelpers>();
                //验证
                services
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            // 當驗證失敗時,回應標頭會包含 WWW-Authenticate 標頭,這裡會顯示失敗的詳細錯誤原因
            options.IncludeErrorDetails = true; // 預設值為 true,有時會特別關閉
    
            options.TokenValidationParameters = new TokenValidationParameters
            {
                // 透過這項宣告,就可以從 "sub" 取值並設定給 User.Identity.Name
                NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
                // 透過這項宣告,就可以從 "roles" 取值,並可讓 [Authorize] 判斷角色
                RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
    
                // 一般我們都會驗證 Issuer
                ValidateIssuer = true,
                ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"),
    
                // 通常不太需要驗證 Audience
                ValidateAudience = false,
                //ValidAudience = "JwtAuthDemo", // 不驗證就不需要填寫
    
                // 一般我們都會驗證 Token 的有效期間
                ValidateLifetime = true,
    
                // 如果 Token 中包含 key 才需要驗證,一般都只有簽章而已
                ValidateIssuerSigningKey = false,
    
                // "1234567890123456" 應該從 IConfiguration 取得
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey")))
            };
        });
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseSwagger();
                    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication1 v1"));
                }
    
                app.UseRouting();
                //验证
                app.UseAuthentication();
                //授权
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
        }
    }

     

  5. 添加一个控制器,在控制器中写语句

    using JwtAuthDemo.Helpers;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using WebApplication1.Models;
    
    namespace WebApplication1.Controllers
    {
        [Authorize]
        [Route("api/[controller]/[action]")]
        [ApiController]
        public class LoginController : ControllerBase
        {
            private readonly JwtHelpers _jwtHelpers;
            public LoginController(JwtHelpers jwtHelpers)
            {
                _jwtHelpers = jwtHelpers;
            }
            //任何请求都可以访问该方法
            [AllowAnonymous]
            [HttpPost]
            public IActionResult Login(LoginDtoModel loginDtoModel)
            {
                if(ValidateUser(loginDtoModel))
                {
                    var token = _jwtHelpers.GenerateToken(loginDtoModel.UName);
                    HttpContext.Response.Headers.Add("token", token);
                    return Ok();
                }
                else
                {
                    return BadRequest();
                }
            }
            [HttpGet]
            public bool ValidateUser(LoginDtoModel loginDtoModel)
            {
                return true;
            }
            [Authorize]
            [HttpGet]
            public IActionResult Test()
            {
                return Ok("Test");
            }
            [HttpGet]
            public IActionResult GetClaims()
            {
                return Ok(User.Claims.Select(m => new { m.Type, m.Value }));
            }
            [HttpGet]
            public IActionResult GetUser()
            {
                return Ok(User.Identity.Name);
            }
        }
    }

     

  6. 注意:[Authorize]需引用using Microsoft.AspNetCore.Authorization; 且获取密钥的方法必须有

    //任何请求都可以访问该方法
    [AllowAnonymous]

posted @ 2021-11-09 15:00  古之召虎  阅读(58)  评论(0)    收藏  举报