ASP.NET Core 3.1中使用JWT身份認證


0、引言

若不清楚什么是JWT的請先了解下什么是JWT

1、關於Authentication與Authorization

我相信在aspnet core中剛接觸甚至用了段時間這兩個概念的時候都是一頭霧水的,傻傻分不清。
認證(Authentication)和授權(Authorization)在概念上比較的相似,且又有一定的聯系,因此很容易混淆。
認證(Authentication)是指驗證用戶身份的過程,即當用戶要訪問受保護的資源時,將其信息(如用戶名和密碼)發送給服務器並由服務器驗證的過程。
授權(Authorization)是驗證一個已通過身份認證的用戶是否有權限做某件事情的過程。
有過RBAC的開發經驗者來說這里可以這么通俗的來理解:認證是驗證一個用戶是否“合法”(一般就是檢查數據庫中是否有這么個用戶),授權是驗證這個用戶是否有做事情的權限(簡單理解成RBAC中的用戶權限)。

2、整個認證流程是怎樣的?

整個HTTP請求流程
從圖中可以看到整個認證、授權的流程,先進行身份驗證 ,驗證通過后將Token放回給客戶端,客戶端訪問資源的時候請求頭中添加Token信息,服務器進行驗證並於授權是否能夠訪問該資源。

3、開始JWT身份認證

3.1 安裝JwtBearer包

在.csproj項目中添加JWT包(這里添加有很多種方式,自行選擇)

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />

3.2 安裝Swashbuckle.AspNetCore包

這里便於進行測試,引入Swagger工具。

<PackageReference Include="Swashbuckle.AspNetCore" Version="5.3.1" />

3.3 添加身份認證相關服務到容器中

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = false,
        ValidateAudience = false,
        ValidateLifetime = false,
        ValidateIssuerSigningKey = true,
        ValidIssuer = "jonny",
        ValidAudience = "jonny",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretsecretsecret"))
    };
});

說明

配置項 類型 說明
ValidateIssuerSigningKey bool 是否調用對簽名securityToken的SecurityKey進行驗證。
ValidIssuer string 將用於檢查令牌的發行者是否與此發行者相同。
ValidateIssuer bool 是否驗證發行者
ValidAudience string 檢查令牌的受眾群體是否與此受眾群體相同。
ValidateAudience bool 在令牌驗證期間驗證受眾 。
ValidateLifetime bool 驗證生命周期。

3.4 添加Swagger服務到容器中

services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("openapi", new Microsoft.OpenApi.Models.OpenApiInfo
    {
        Title = "統一身份認證API",
        Description = "身份認證和授權詳解",
        Version = "v1"
    });
    var scheme = new OpenApiSecurityScheme()
    {
        Scheme = JwtBearerDefaults.AuthenticationScheme,
        BearerFormat = "JWT",
        In = ParameterLocation.Header,
        //頭名稱
        Name = ApiKeyConstants.HeaderName,
        Type = SecuritySchemeType.ApiKey,
        Description = "Bearer Token"
};
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, scheme);
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
 {
     {
         new OpenApiSecurityScheme
         {
             Reference = new OpenApiReference
             {
                 Type = ReferenceType.SecurityScheme,
                 Id = "Bearer"
             }
         },
         new string[] {}
     }
 });
});

aspnet core 3.x swagger與2.x有細微的差別,例如swagger中加入jwt和以前就有一定的差別。

swagger加入身份認證后出現了認證按鈕。
在這里插入圖片描述

3.5 將身份認證加入到管道中

//身份認證中間件(踩坑:授權中間件必須在認證中間件之前)
app.UseAuthentication();

3.x中身份認證一定要在UseRouting和UseEndpoints之間

3.6 將swagger加入到管道中

app.UseSwagger();
app.UseSwaggerUI(options =>
{
     options.RoutePrefix = string.Empty;
     //配置swagger端點
     options.SwaggerEndpoint("swagger/openapi/swagger.json", "openapi v1");
});

3.7 在需要授權的資源上加入Authorize

例如:

[HttpGet("role")]
[Authorize(Roles = "admin")]
public IEnumerable<Claim> GetRole()
{
    return HttpContext.User.FindAll(c => c.Type == ClaimTypes.Role);
}

這里默認使用角色授權機制

4 、測試

4.1 請求資源

這時會返回401,因為沒有進行身份認證
在這里插入圖片描述

4.2 調用登錄獲取token

在這里插入圖片描述

4.3 將token添加到Header中

在這里插入圖片描述

4.4 再次請求

這時返回403,是因為使用的jonny賬戶登錄的沒有admin權限。
在這里插入圖片描述

4.5 切換admin賬戶登錄

在這里插入圖片描述
重復上面的4.3、4.4步驟 。再次測試。這時就能正常訪問。
在這里插入圖片描述

5、登錄邏輯代碼

我這里就不做過多的解釋 ,直接將相關創建JTW代碼等貼出來。

public interface ICustomAuthenticationManager
{
    string Authenticate(string username, string password);

    IDictionary<string, string> Tokens { get; }
}
public class CustomAuthenticationManager : ICustomAuthenticationManager
{
    private readonly IDictionary<string, string> users = new Dictionary<string, string>
    {
        { "admin", "admin" },
        { "jonny", "jonny" },
        { "xhl", "xhl" },
        { "james", "james" }
    };

    public IDictionary<string, string> Tokens { get; } = new Dictionary<string, string>();

    public string Authenticate(string username, string password)
    {
        var claimsIdentity = new ClaimsIdentity(new[]{
            new Claim(ClaimTypes.Name,username)
        });
        if (!users.Any(u => u.Key == username && u.Value == password))
        {
            return null;
        }
        if (username == "admin")
        {
            claimsIdentity.AddClaims(new[]
            {
                new Claim( ClaimTypes.Email, "xhl.jonny@gmail.com"),
                new Claim( "ManageId", "admin"),
                new Claim(ClaimTypes.Role,"admin")
            });
        }
        var handler = new JwtSecurityTokenHandler();
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = claimsIdentity,
            Expires = DateTime.Now.AddMinutes(3),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secretsecretsecret")), SecurityAlgorithms.HmacSha256),
        };
        var securityToken = handler.CreateToken(tokenDescriptor);
        var token = handler.WriteToken(securityToken);
        Tokens.Add(token, username);
        return token;
    }
}

上面使用內存數據進行邏輯驗證 ,實際中需要使用數據庫查詢驗證等。

今天的JWT身份認證就介紹完了 ,下一篇文章將介紹授權。角色授權、身份授權(Claim)、自定義策略授權。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM