Asp.net Core認證和授權:JWT認證和授權


JWT驗證一般用戶移動端,因為它不像cookie驗證那樣,沒有授權跳轉到登陸頁面

JWT是json web token的簡稱,在  jwt.io 網址可以看到

 

 

 

 

新建一個API項目,通過postman 可以訪問:

 

 JWT在命名空間:using Microsoft.AspNetCore.Authentication.JwtBearer;

添加JWT實體類

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Api.Models
{
    public class JwtSettings
    {
        /// <summary>
        /// Token是誰頒發的
        /// </summary>
        public string Issuer { get; set; }

        /// <summary>
        /// Token給那些客戶端去使用
        /// </summary>
        public string Audience { get; set; }

        /// <summary>
        /// 用於加密的key 必須是16個字符以上,要大於128個字節
        /// </summary>
        public string SecetKey { get; set; }
    }
}

 

 

添加配置文件

 

 

 

 

添加JWT認證

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.Configure<JwtSettings>(Configuration);

            var jwtSettings = new JwtSettings();
            Configuration.Bind("JwtSettings", jwtSettings);

            services.AddAuthentication(option => {
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(option=> {
                option.TokenValidationParameters = new TokenValidationParameters {
                    ValidIssuer = jwtSettings.Issuer,
                    ValidAudience = jwtSettings.Audience,
                    IssuerSigningKey=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecetKey))


 /***********************************TokenValidationParameters的參數默認值***********************************/
                    // RequireSignedTokens = true,
                    // SaveSigninToken = false,
                    // ValidateActor = false,
                    // 將下面兩個參數設置為false,可以不驗證Issuer和Audience,但是不建議這樣做。
                    // ValidateAudience = true,
                    // ValidateIssuer = true,
                    // ValidateIssuerSigningKey = false,
                    // 是否要求Token的Claims中必須包含Expires
                    // RequireExpirationTime = true,
                    // 允許的服務器時間偏移量
                    // ClockSkew = TimeSpan.FromSeconds(300),
                    // 是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比
                    // ValidateLifetime = true }; }); }

 

添加中間件(Middleware)

 app.UseAuthentication();

 

API接口打上標簽:

 

 

 然后在postman訪問 就是401 未授權

 

 接下來需要給用戶頒發Token

當用戶登陸成功后,頒發token

創建登陸API和實體類

namespace Api.Models
{
    public class LoginViewModel
    {
        [Required]
        public string user { get; set; }
        [Required]
        public string pwd { get; set; }
    }
}
using Api.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Api.Controllers
{
    //[Route("api/[controller]")]
    //[ApiController]
    public class AuthorizeController : ControllerBase
    {
        private JwtSettings _jwtSettings;
        public AuthorizeController(IOptions<JwtSettings> jwtSetting)
        {
            _jwtSettings = jwtSetting.Value;
        }

        [HttpPost]
        public IActionResult Token([FromBody]LoginViewModel login)
        {
            if (ModelState.IsValid)
            {
                if (!(login.user == "cnglgos" && login.pwd == "123"))
                {
                    return BadRequest();
                }
                var claim = new Claim[] {
                    new Claim("name","cnbogs"),
                    new Claim("role","admin")
                };

                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                //neget包:Microsoft.AspNetCore.Authentication.JwtBearer
                //命名空間: System.IdentityModel.Tokens.Jwt;

                //第一種方式
                var token = new JwtSecurityToken(
                    _jwtSettings.Issuer,// Issuer 頒發者,通常為STS服務器地址
                    _jwtSettings.Audience,// Audience Token的作用對象,也就是被訪問的資源服務器授權標識
                    claim,
                    DateTime.Now,  //Token生效時間,在此之前不可用
                    DateTime.Now.AddMinutes(30), //Token過期時間,在此之后不可用
                    creds);

                //第二種方式
                var descriptor = new SecurityTokenDescriptor
                {
                    Issuer = _jwtSettings.Issuer,
                    Audience = _jwtSettings.Audience,// Audience Token的作用對象,也就是被訪問的資源服務器授權標識
                    Subject = new ClaimsIdentity(claim),
                    NotBefore = DateTime.Now, //Token生效時間,在此之前不可用
                    Expires = DateTime.Now.AddMinutes(30), //Token過期時間,在此之后不可用
                    SigningCredentials = creds,
                    IssuedAt=DateTime.Now //Token頒發時間
                };
                var handler = new JwtSecurityTokenHandler();
                JwtSecurityToken token1 = handler.CreateJwtSecurityToken(descriptor);


                return Ok(new
                {
                    token = new JwtSecurityTokenHandler().WriteToken(token),
                    token1 = handler.WriteToken(token1)
                });
            }
            return BadRequest();
        }

        public IActionResult Index()
        {
            return Ok();
        }
    }
}

 

 

Postman請求

 

 

然后上面的Token 請求 https://localhost:5001/api/values

 

 

從headers可以看到,前綴必須是Bearer

 

 

我們可以自定義Token,必須繼承接口:ISecurityTokenValidator

 

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Collections.Generic;
using System.Security.Claims;
namespace Api.Models
{
    public class TokenValidtor : ISecurityTokenValidator
    {
        public bool CanValidateToken => true;

        public int MaximumTokenSizeInBytes { get; set; }

        public bool CanReadToken(string securityToken)
        {
            return true;
        }

        public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
           validatedToken = null;

            var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);

            if (securityToken == "cnblgos")
            {
                var claim = new List<Claim> {
                    new Claim("name","cnblogs"),
                    new Claim("role","admin")
                };
                identity.AddClaims(claim);
            }

            var principal = new ClaimsPrincipal(identity);
            return principal; } } }

然后在StartUp中修改:

  public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            /*
             appsettings.json文件中JwtSettings是單獨的一節,
             所以要GetSection方法獲取
             */
            services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings"));

            //services.Configure<JwtSettings>(Configuration);

            var jwtSettings = new JwtSettings();
            Configuration.Bind("JwtSettings", jwtSettings);

            services.AddAuthentication(option =>
            {
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(option =>
            {
                //option.TokenValidationParameters = new TokenValidationParameters {
                //    ValidIssuer = jwtSettings.Issuer,
                //    ValidAudience = jwtSettings.Audience,
                //    IssuerSigningKey=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))



                option.SecurityTokenValidators.Clear();
                option.SecurityTokenValidators.Add(new TokenValidtor());
                option.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var token = context.Request.Headers["token"];
                        context.Token = token.FirstOrDefault();
                        return Task.CompletedTask;
                    }
    
                };
            });

        }

 

 

   //添加Policy和Claim授權
            services.AddAuthorization(options => {
                options.AddPolicy("nsky", policy => policy.RequireClaim("nsky")); });

 

 

 

 

Token可以去jwt.io 網站驗證

 

 

 參考大神的文章:https://www.cnblogs.com/RainingNight/p/jwtbearer-authentication-in-asp-net-core.html

 


免責聲明!

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



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