1、建.NetCore的WebApi项目,安装包IdentityModel,Microsoft.AspNetCore.Authentication.JwtBearer,Microsoft.AspNetCore.Authorization
2、注册服务和中间件

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;
using System.Threading.Tasks;

namespace WebApiJwt.Utils
{
    public static class AuthorizationSetup
    {
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            // 策略
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Admin", policy => policy.RequireRole("Admin", "System"));
            });

            //读取配置文件
            var symmetricKeyAsBase64 = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = ConfigHelper.GetSectionValue("JwtSetting:Issuer");
            var Audience = ConfigHelper.GetSectionValue("JwtSetting:Audience");

            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,//是否验证签名,不验证的画可以篡改数据,不安全
                IssuerSigningKey = signingKey,//解密的密钥
                ValidateIssuer = true,//是否验证发行人,就是验证载荷中的Iss是否对应ValidIssuer参数
                ValidIssuer = Issuer,//发行人
                ValidateAudience = true,//是否验证订阅人,就是验证载荷中的Aud是否对应ValidAudience参数
                ValidAudience = Audience,//订阅人
                ValidateLifetime = true,//是否验证过期时间,过期了就拒绝访问
                ClockSkew = TimeSpan.Zero,//缓冲过期时间,真正过期时间=配置过期时间+缓冲过期时间,默认5分钟
                RequireExpirationTime = true,//token需要设置过期时间
            };

            // 开启Bearer认证,添加JwtBearer服务
            services.AddAuthentication(o =>
            {
                o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o =>
            {
                o.TokenValidationParameters = tokenValidationParameters;
                o.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        // 如果过期,则把<是否过期>添加到,返回头信息中
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
            });
        }
    }
}

 Startup.cs
注册服务:services.AddAuthorizationSetup();
添加中间件:app.UseAuthentication(); app.UseAuthorization();
3、生成Token

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

namespace WebApiJwt.Utils
{
    public class JwtHelper
    {
        /// <summary>
        /// 颁发JWT字符串
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static object IssueJwt(TokenModel tokenModel)
        {
            DateTime authTime = DateTime.UtcNow;
            string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");//颁发者
            string aud = ConfigHelper.GetSectionValue("JwtSetting:Audience");//可以给哪些客户端使用
            string secret = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");//加密的Key
            //token有效期 分钟
            DateTime expiresAt = authTime.AddMinutes(Convert.ToDouble(ConfigHelper.GetSectionValue("JwtSetting:ExpireMinutes")));

            //设置Claim
            var claims = new List<Claim>
            {
                //claim默认配置
                new Claim(JwtRegisteredClaimNames.Jti, tokenModel.UserId.ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}") ,

                //过期时间,JWT有缓冲过期时间,所以过期时间到了会延迟一会儿再过期,影响不大。
                new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(expiresAt).ToUnixTimeSeconds()}"),
                new Claim(ClaimTypes.Expiration, expiresAt.ToString()),

                new Claim(JwtRegisteredClaimNames.Iss,iss),//颁发者
                new Claim(JwtRegisteredClaimNames.Aud,aud),//可以给哪些客户端使用

                new Claim(ClaimTypes.Name, tokenModel.UserName),
                new Claim(ClaimTypes.Email, tokenModel.Email)
            };
            //设置Claim角色
            claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

            //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwtSecurityToken = new JwtSecurityToken(issuer: iss, claims: claims, signingCredentials: creds);
            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwtSecurityToken);
            //存储 Token 信息
            var jwt = new
            {
                UserId = tokenModel.UserId,
                Token = encodedJwt,
                Auths = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
                Expires = new DateTimeOffset(expiresAt).ToUnixTimeSeconds(),
                Success = true
            };
            return jwt;
        }

        /// <summary>
        /// 解析
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static TokenModel SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            if (!jwtHandler.CanReadToken(jwtStr)) { return null; }
            string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            if (jwtToken.Issuer != iss)
            {
                return null;//不正确
            }
            if (jwtToken.ValidTo < DateTime.UtcNow)
            {
                return null;//过期
            }
            object role, userName, email;
            try
            {
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
                jwtToken.Payload.TryGetValue(ClaimTypes.Name, out userName);
                jwtToken.Payload.TryGetValue(ClaimTypes.Email, out email);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            var tm = new TokenModel
            {
                UserId = jwtToken.Id.ToString(),
                Role = role != null ? role.ToString() : "",
                UserName = userName != null ? userName.ToString() : "",
                Email = email != null ? email.ToString() : ""
            };
            return tm;
        }
    }
}

 配置

"JwtSetting": {
    "Issuer": "jwtIssuer", //颁发者
    "Audience": "jwtAudience", //可以给哪些客户端使用
    "SecretKey": "abcdabcdabcdabcdabcdabcdabcdabcd", //加密的Key,长度最少要32位,不然报错。
    "ExpireMinutes": "3" //token有效期3分钟
}

 辅助

using Microsoft.Extensions.Configuration;
using System;

namespace WebApiJwt.Utils
{
    public class ConfigHelper
    {
        public readonly static IConfiguration configuration;
        static ConfigHelper()
        {
            configuration = new ConfigurationBuilder()
            .SetBasePath(Environment.CurrentDirectory)
            .AddJsonFile("appsettings.json", true, true)
            .AddInMemoryCollection()
            .Build();
        }
        public static string GetSectionValue(string key)
        {
            return configuration[key];
        }
        public static string connectionString
        {
            get { return configuration["ConnectionStrings:Default"]; }
        }
    }
}

 4、ApiController

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using WebApiJwt.Models;
using WebApiJwt.Utils;

namespace WebApiJwt.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class AuthorizeController : ControllerBase
    {
        /// <summary>
        /// 生成令牌
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public string GenToken()
        {
            TokenModel tokenModel = new TokenModel { UserId = "1001", Role = "Admin", Email = "908085411@qq.com", UserName = "邢帅杰" };
            string jwtToken = JsonConvert.SerializeObject(JwtHelper.IssueJwt(tokenModel));
            return jwtToken;
        }

        /// <summary>
        /// 需要Admin权限
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Authorize(Roles = "Admin")]
        //[Authorize(Policy = "Admin")]//使用策略来映射多个角色
        public IActionResult Admin()
        {
            return Ok("admin........");
        }

        /// <summary>
        /// 解析Token
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public IActionResult AnalysisToken()
        {
            var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
            var user = JwtHelper.SerializeJwt(tokenHeader);
            return Ok(user);
        }
    }
}

5、 生成:https://localhost:44393/api/Authorize/GenToken,解析:https://localhost:44393/api/Authorize/AnalysisToken,在header中添加 Authorization:Bearer token
参考:

https://www.cnblogs.com/danvic712/p/10331976.html
https://blog.csdn.net/weixin_42045719/article/details/91973878
http://cn.voidcc.com/question/p-vckjdtzx-hv.html
https://www.cnblogs.com/danvic712/p/10331976.html
https://blog.csdn.net/baidu_35726140/article/details/84867520
https://www.cnblogs.com/xwc1996/p/14058115.html

posted on 2021-09-30 17:42  邢帅杰  阅读(209)  评论(0编辑  收藏  举报