zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    vsprintf解析
    带grub的软盘镜像制作
    SunnyOS准备4
    SunnyOS准备3
    SunnyOS准备1
    汇编第七日
    汇编第六日
    解决k8s集群中mount volume失败的问题
    更新k8s集群的证书
    为k8s集群配置自定义告警
  • 原文地址:https://www.cnblogs.com/nsky/p/10312101.html
Copyright © 2011-2022 走看看