.NetCore WebApi——基于JWT的简单身份认证与授权(Swagger)

目录:

.NetCore WebApi——Swagger简单配置

.NetCore WebApi——基于JWT的简单身份认证与授权(Swagger)

.NetCore WebApi —— Swagger版本控制

任何项目都有权限这一关键部分。比如我们有许多接口。有的接口允许任何人访问,另有一些接口需要认证身份之后才可以访问;以保证重要数据不会泄露。

关于JWT

维基百科上是这样定义的:

JWT(读作 [/dʒɒt/]),即JSON Web Tokens,是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。它是一种用于双方之间传递安全信息的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的、自包含的方法,从而使通信双方实现以JSON对象的形式安全的传递信息。

认证的工作流程:

1. 客户端携带用户名、密码向授权服务申请 "令牌(token)"

2.授权服务器验证用户名、密码后根据它的身份生成一张专属的 "令牌" 并JWT的格式规范返回给客户端

3.客户端将获取到的令牌放入到http的请求头中,然后向资源服务器发起请求。服务器根据客户端发送过来的令牌来进行下一步处理(根据身份来响应客户端是否具有当前接口的权限)

如下图所示:

 正文:

主要参考园友  在7楼  的这篇文章 https://www.cnblogs.com/RayWang/p/9536524.html 

 1. 启用Swagger的验证功能

在startup类中新添加红色部分代码。启动项目观察效果。

复制代码
// 注册Swagger服务
            services.AddSwaggerGen(c =>
            {
                // 添加文档信息
                c.SwaggerDoc("v1", new Info
                {
                    Title = "CoreWebApi",
                    Version = "v1",
                    Description = "ASP.NET CORE WebApi",
                    Contact = new Contact
                    {
                        Name = "Jee",
                        Email = "xiaomaprincess@gmail.com",
                        Url = "https://www.cnblogs.com/jixiaosa/"
                    }
                });

                #region 读取xml信息

                // 使用反射获取xml文件。并构造出文件的路径
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                // 启用xml注释. 该方法第二个参数启用控制器的注释,默认为false.
                c.IncludeXmlComments(xmlPath, true);
                #endregion

                #region 启用swagger验证功能
                //添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称一致即可,CoreAPI。
                var security = new Dictionary<string, IEnumerable<string>> { { "CoreAPI", new string[] { } }, };
                c.AddSecurityRequirement(security);
                c.AddSecurityDefinition("CoreAPI", new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",
                    Name = "Authorization",//jwt默认的参数名称
                    In = "header",//jwt默认存放Authorization信息的位置(请求头中)
                    Type = "apiKey"
                });
                #endregion

            });
复制代码

没启动Swagger验证之前是这样的:

启用验证之后再看:多了个小按钮

点开之后是如下界面:文本框里要如输入从服务器获取的Token。格式为:Bearer + 空格+token。 Bearer可以看作是一个默认的规则。

2.生成token

.net core 内置了许多帮助类,巧妙的使用这些类组合,就可以生成我们想要的 token

新建一个tokenl类,编写一个方法来获取JWT字符串

复制代码
 /// <summary>
    /// 生成JWT字符串
    /// </summary>
    public class Token
    {
        // 密钥,注意不能太短
        public static string secretKey { get; set; } = "xiaomaPrincess@gmail.com";
        /// <summary>
        /// 生成JWT字符串
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string GetJWT(TokenModel tokenModel)
        {
            //DateTime utc = DateTime.UtcNow;
            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Jti,tokenModel.ID.ToString()),
                // 令牌颁发时间
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                 // 过期时间 100秒
                new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(100)).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Iss,"API"), // 签发者
                new Claim(JwtRegisteredClaimNames.Aud,"User") // 接收者
            };

            
            // 密钥
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var tokenHandler = new JwtSecurityTokenHandler();

            JwtSecurityToken jwt = new JwtSecurityToken(
                
                claims: claims,// 声明的集合
                //expires: .AddSeconds(36), // token的有效时间
                signingCredentials: creds
                );
            var handler = new JwtSecurityTokenHandler();
            // 生成 jwt字符串
            var strJWT = handler.WriteToken(jwt);
            return strJWT;
        }
}
复制代码

基本信息类

复制代码
 public class TokenModel
    {
        /// <summary>
        /// ID
        /// </summary>
        public int ID { get; set; }
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 手机
        /// </summary>
        public string Phone { get; set; }
        /// <summary>
        /// 邮箱
        /// </summary>
        public string Email { get; set; }
        /// <summary>
        /// 身份
        /// </summary>
        public string Sub { get; set; }
    }
复制代码

添加一个方法来获取token

复制代码
/// <summary>
        /// 获取令牌
        /// </summary>
        /// <param name="ID">ID</param>
        /// <param name="name">账号</param>
        /// <returns></returns>
        [HttpPost]
        public string GetJwt(int ID,string name)
        {
            TokenModel tokenModel = new TokenModel
            {
                ID = ID,
                Name=name
            };

            return Token.GetJWT(tokenModel);
        }
复制代码

在Startup类中配置身份认证服务

(1)在ConfigureServices方法中注册服务

复制代码
 #region 添加验证服务

            // 添加验证服务
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    // 是否开启签名认证
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Token.secretKey)),
                    // 发行人验证,这里要和token类中Claim类型的发行人保持一致
                    ValidateIssuer = true,
                    ValidIssuer = "API",//发行人
                    // 接收人验证
                    ValidateAudience = true,
                    ValidAudience = "User",//订阅人
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero,
                };
            });
            #endregion
复制代码

(2)在Configure方法中启用验证中间件

复制代码
   // 启用Swagger中间件
            app.UseSwagger();
            // 配置SwaggerUI
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "CoreAPI");
                c.RoutePrefix = string.Empty;
            });
            // 启用认证中间件
            app.UseAuthentication();
            app.UseMvc();
复制代码

3. 添加一个测试测控制器来检测是否成功

注意要添加 [Authorize]标签

复制代码
  /// <summary>
    /// 需要身份认证的控制器
    /// </summary>
    [Route("api/[controller]/[action]")]
    [Produces("application/json")]
    [ApiController]
    [Authorize]// 添加授权特性
    public class TestController : ControllerBase
    {
        /// <summary>
        /// 认证通过之后可访问
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult<TokenModel> Get(TokenModel tokenModel)
        {
            return new TokenModel{ ID=1 };
        }

    }
复制代码

启动项目

测试一: 在没有获取token时访问此方法

 返回401 身份验证未通过

测试二:先访问GetJWT接口获取token,在访问Test接口

最后将获取的token输入到Swagger的文本框中:Bearer +空格+Token

 再次访问Test接口:成功返回数据

至此,一个简单身份认证加授权就完成了。

推荐一篇大神的文章 :讲述Claim的

理解ASP.NET Core验证模型(Claim, ClaimsIdentity, ClaimsPrincipal)不得不读的英文博文

源码:GitHub

https://github.com/xiaoMaPrincess/Asp.NetCore-WebApi

多层架构版本:

https://github.com/xiaoMaPrincess/.NetCoreWebApi

原作者是:千金不如一默

原文地址:https://www.cnblogs.com/spring_wang/p/13212959.html