1. 程式人生 > 實用技巧 >.net core3.1中實現簡單的jwt認證

.net core3.1中實現簡單的jwt認證

1.建立專案

使用visual studio建立一個名為JwtDemo的空專案,建立後如圖

2.新增依賴項

  • 在nuget包管理器中搜索 Microsoft.AspNetCore.Authentication.JwtBearer、System.IdentityModel.Tokens.Jwt
  • 在nuget包管理控制檯安裝
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 3.1.7
Install-Package System.IdentityModel.Tokens.Jwt -Version 6.7.1

3.編寫程式碼

建立一個介面(IJwtAuthenticationHandler),宣告一個用於建立token的方法(Authenticate)

namespace JwtDemo
{
    public interface IJwtAuthenticationHandler
    {
        string Authenticate(string username, string password);
    }
}

建立一個類,繼承介面(IJwtAuthenticationHandler),並實現方法,這裡簡單起見就將使用者硬編碼在程式碼中

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;

using Microsoft.IdentityModel.Tokens;

namespace JwtDemo
{
    public class JwtAuthenticationHandler: IJwtAuthenticationHandler
    {
        private readonly IDictionary<string, string> users = new Dictionary<string, string>()
        {
            {"user1","password1"},
            {"user2","password2"},
        };

        private readonly string _token;   //宣告一個加密的金鑰,由外部傳入

        public JwtAuthenticationHandler(string token)
        {
            _token = token;
        }

        public string Authenticate(string username, string password)
        {
            //如果使用者名稱密碼錯誤則返回null
            if (!users.Any(t => t.Key == username && t.Value == password))
            {
                return null;
            }
            var tokenKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_token));
            var tokenHandler = new JwtSecurityTokenHandler();
            var tokenDescriptor = new SecurityTokenDescriptor()
            {
                SigningCredentials = new SigningCredentials(tokenKey, SecurityAlgorithms.HmacSha256),
                Expires = DateTime.Now.AddMinutes(10), 
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name,username),
                })
            };

            var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }
    }
}

修改Startup類

using System.Text;

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;

namespace JwtDemo
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            string tokenSecretKey = "this is a test token secret key"; //加密的金鑰
            services.AddAuthentication(config =>
            {
                //認證方案設定為Jwt
                config.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                config.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(config=>
            {
                config.RequireHttpsMetadata = false;
                config.SaveToken = true;  //儲存token
                config.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateIssuer = false,//不驗證簽發人
                    ValidateAudience = false,  //不驗證聽眾
                    ValidateIssuerSigningKey = true, //驗證簽發者金鑰
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenSecretKey)) //簽發者金鑰
                };
            });
            //將生成token的類註冊為單例
            services.AddSingleton<IJwtAuthenticationHandler>(new JwtAuthenticationHandler(tokenSecretKey));
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

建立一個控制器(UserController),包含一個認證方法和一個獲取使用者列表(加了許可權認證)的方法

using System.Collections.Generic;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace JwtDemo.Controllers
{
    [ApiController]
    public class UserController: Controller
    {
        private readonly IJwtAuthenticationHandler _jwtAuthenticationHandler;
        //建構函式注入生成token的類
        public UserController(IJwtAuthenticationHandler jwtAuthenticationHandler)
        {
            _jwtAuthenticationHandler = jwtAuthenticationHandler;
        }

        [AllowAnonymous]  //表示可以匿名訪問
        [Route("user/authenticate")]
        [HttpPost]
        public IActionResult Authenticate([FromBody] LoginViewModel loginViewModel)
        {
            var token = _jwtAuthenticationHandler.Authenticate(loginViewModel.UserName,loginViewModel.Password);
            if (token == null)
            {
                return Unauthorized();
            }
            return Ok(token);
        }

        [Authorize]   //表示需要認證授權訪問
        [Route("user/list")]
        [HttpGet]
        public List<object> List()
        {
            return new List<object>()
            {
                "user1","user2","user3","user..."
            };
        }
    }
}

LoginViewModel類

namespace JwtDemo.Controllers
{
    public class LoginViewModel
    {
        public string UserName { get; set; }
        public string Password { get; set; }
    }
}

完成後的專案結構

4.測試介面

執行專案,我們直接請求使用者列表的介面,返回401,表示未授權

我們請求認證介面進行認證,輸入正確的使用者名稱和密碼,會返回一個token

使用上面的token再次請求使用者列表介面,將Header中加入Authorization:Bearer token,可以正常返回資料,表示已經成功