zoukankan      html  css  js  c++  java
  • WebApi程序,关于请求的身份验证问题

    接上一篇,在我们创建好WebApi程序之后,可以通过PostMan或者直接通过浏览器去请求我们的接口。这个时候涉及到一个问题,如何确定请求者的身份呢?

    在这里我们使用JWT,在登陆后,给用户颁发一个访问其他接口的身份令牌,每一次的请求必须带令牌请求,否则请求无效。

    实现步骤如下:

    1.首先我们需要拦截到每一次的请求,然后对请求做分析

    在这里我们引入using Microsoft.AspNetCore.Http ,主要是要用到HttpContext类

    public class JwtAuthorizationFilter
        {
            //RequestDelegate请求委托
            private readonly RequestDelegate _next;
            public JwtAuthorizationFilter(RequestDelegate next)
            {
                _next = next;
            }
    
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="httpContext"></param>
            /// <returns></returns>
            public Task Invoke(HttpContext httpContext)
    
            {
                //对请求信息进行处理部分
                return _next(httpContext);
            }
        }

    上面代码里 HttpContext httpContext 可以获取到对接口的请求,请求信息包括在httpContext里,在获取到请求之后我们要对请求进行一个处理,即,解析出该请求用户的身份信息

    回到用户登陆模块,用在登陆的时候我们要给他授权一个身份令牌,并返回一个token字符串给用户(后期球球任何接口都要带上该字符串),我们在用户登陆写个登陆实现

     /// <summary>
            /// 用户登录实现
            /// </summary>
            /// <param name="parm"></param>
            /// <returns></returns>
            public async Task<ApiResult<Result>> LoginAsync(TUserAuthsLogin parm)
            {
                var res = new ApiResult<Result>();
                //用户名是否存在
                var model = Db.Queryable<T_User_Auths>()
                        .Where(m => m.LoginName == parm.LoginName).First();
                //校验用户类型和密码
                if (model != null && model.UseState == 1)
                {
                    if (model.PassWord.Equals(parm.PassWord))
                    {
                        //校验过用户名和密码之后,给用户颁发身份令牌并返回token字符串给用户
                        TokenModel tokenModel = new TokenModel();
                        tokenModel.Uid = model.UserId;//UID
                        tokenModel.LoginName = model.LoginName;//用户名
                        string tokenStr = JwtHelper.IssueJWT(tokenModel);
    
                        res.success = true;
                        res.token = tokenStr;//返回token字符串给用户
                        res.message = "登录成功!";
                        
                    }
                    else
                    {
                        res.success = false;
                        res.statusCode = (int)ApiEnum.Error;
                        res.message = "密码错误~";
                    }
                }
                else
                {
                    res.success = false;
                    res.statusCode = (int)ApiEnum.Error;
                    res.message = "账号错误~";
                }        
                return await Task.Run(() => res);
            }

    在校验过用户名和密码之后,颁发,令牌,将令牌放进JWT帮助类,生成token字符串

    JWTHelper如下

    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 System.Threading.Tasks;
    
    namespace SupplierManagement.Helper.JWT
    {
        public class JWTHelper
        {
            /// <summary>
            /// .net core 自带了jwt帮助类
            /// </summary>
            public class JwtHelper
            {
    
                /// <summary>
                /// 颁发JWT字符串
                /// </summary>
                /// <param name="tokenModel"></param>
                /// <returns></returns>
                public static string IssueJWT(TokenModel tokenModel)
                {
                    var dateTime = DateTime.UtcNow;//世界时间
                    var claims = new Claim[]
                    {
                    new Claim(JwtRegisteredClaimNames.Jti,tokenModel.Uid.ToString()),//用户Id
                    new Claim("TokenType",tokenModel.TokenType),
                    new Claim("LoginName",tokenModel.LoginName),
                    //new Claim("Role", tokenModel.Role),//身份
                    //new Claim("Project", tokenModel.Project),//访问项目
                    new Claim(JwtRegisteredClaimNames.Iat,dateTime.ToString(),ClaimValueTypes.Integer64)//时间戳
                    };
                    //秘钥
                    var jwtConfig = new JwtAuthConfigModel();
                    //(获取用于签名的验证)
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.JWTSecretKey));
                    //获取与Microsoft.IdentityModel.Tokens.SecurityKey关联的密钥ID。
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                    //过期时间
                    double exp = 0;
                    switch (tokenModel.TokenType)
                    {
                        case "Web":
                            exp = jwtConfig.WebExp;
                            break;
                        case "App":
                            exp = jwtConfig.AppExp;
                            break;
                        case "MiniProgram":
                            exp = jwtConfig.MiniProgramExp;
                            break;
                        case "Other":
                            exp = jwtConfig.OtherExp;
                            break;
                    }
    
                    var jwt = new JwtSecurityToken(
                        issuer: "NewNanNingSystem",//项目名称
                        claims: claims, //声明集合(包括用户和时间戳)
                        expires: dateTime.AddHours(exp),//expires有效分钟数
                        signingCredentials: creds);//关联密钥id
    
                    var jwtHandler = new JwtSecurityTokenHandler();
                    var encodedJwt = jwtHandler.WriteToken(jwt);//将jwt序列化
    
                    return encodedJwt;
                }
    
                /// <summary>
                /// 解析成令牌模型
                /// </summary>
                /// <param name="jwtStr"></param>
                /// <returns></returns>
                public static TokenModel SerializeJWT(string jwtStr)
                {
                    var jwtHandler = new JwtSecurityTokenHandler();
                    JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
    
                    object role = new object(); ;
                    object user = new object();
                    try
                    {
                        jwtToken.Payload.TryGetValue("TokenType", out role);//没理解
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                    var tm = new TokenModel
                    {
                        Uid = jwtToken.Id,
                        LoginName = jwtToken.Payload["LoginName"].ToString()
                    };
                    return tm;
                }
            }
            /// <summary>
            /// 令牌
            /// </summary>
            public class TokenModel
            {
                /// <summary>
                /// 用户Id
                /// </summary>
                public string Uid { get; set; }
    
                /// <summary>
                /// 用户名
                /// </summary>
                public string LoginName { get; set; }
                /// <summary>
                /// 身份
                /// </summary>
                public string Role { get; set; }
                /// <summary>
                /// 项目名称
                /// </summary>
                public string Project { get; set; }
                /// <summary>
                /// 令牌类型
                /// </summary>
                public string TokenType { get; set; }
            }
        }
    }

    相关联的类,JwtAuthConfigModel

    using SupplierManagement.Common;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace SupplierManagement.Helper.JWT
    {
        public class JwtAuthConfigModel : BaseConfigModel
        {
            /// <summary>
            /// 
            /// </summary>
            public JwtAuthConfigModel()
            {
                try
                {
                    //通过Configuration去读取配置,appsetting里面
                    JWTSecretKey = ConfigurationManager.Configuration["JwtAuth:SecurityKey"];
                    WebExp = double.Parse(ConfigurationManager.Configuration["JwtAuth:WebExp"]);
                    AppExp = double.Parse(ConfigurationManager.Configuration["JwtAuth:AppExp"]);
                    MiniProgramExp = double.Parse(ConfigurationManager.Configuration["JwtAuth:MiniProgramExp"]);
                    OtherExp = double.Parse(ConfigurationManager.Configuration["JwtAuth:OtherExp"]);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
            /// <summary>
            /// JWT密钥
            /// </summary>
            public string JWTSecretKey = "This is JWT Secret Key";
            /// <summary>
            /// 
            /// </summary>
            public double WebExp = 12;
            /// <summary>
            /// 
            /// </summary>
            public double AppExp = 12;
            /// <summary>
            /// 
            /// </summary>
            public double MiniProgramExp = 12;
            /// <summary>
            /// 
            /// </summary>
            public double OtherExp = 12;
        }
    }

    到这一步后,我们还无法使用JWT,我们还需要在startup里面对JWT进行注册

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
                //接口注册
                services.AddTransient<ITUserAuthsService, TUserAuthsService>();
                //JWT注册
                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                    .AddJwtBearer(options => {
                        JwtAuthConfigModel jwtConfig = new JwtAuthConfigModel();
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateIssuer = true,//是否验证Issuer
                            ValidateAudience = true,//是否验证Audience
                            ValidateLifetime = true,//是否验证失效时间
                            ValidateIssuerSigningKey = true,//是否验证SecurityKey
                            ValidAudience = "wangcong",//Audience
                            ValidIssuer = "NewNanNingSystem",//Issuer,这两项和前面签发jwt的设置一致
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.JWTSecretKey))//拿到SecurityKey
                        };
                    });
            }

    注册完成,我们提交一个登陆请求,

    结果如下

    ,好了,到这一步,我们登陆成功了,现在我们需要访问其他接口了,我们得把这个验证身份的字符串带上,我们先写一个查询所有用户的方法,分别在接口,实现,以及控制器写上对应方法

    我们用postman模拟浏览器请求,这个时候记得带上token字符串

    发送请求后,我们进入拦截器

    在这里我们看到,请求的接口是/api/login/getAllUsers,并且请求头里面包含了Authorization属性,我们token字符串是放在这个属性里面的。在这里提一下登陆放行,因为任何请求在这里都会被拦截,包括登陆请求和浏览器的预请求,第一次登陆的时候是不回有token字符串的,这需要我们登陆后进行颁发,所以判断地址进行放行,Method=="OPTIONS"是浏览器的预请求,我们也放行,浏览器的第二次的请求才是真实的接口请求,在这里我们拿到token字符串后,使用JWT帮助类进行解析。结果如下

    在这里我们解析出了用户名和用户id确认了请求者的身份,现在放行请求让他访问我们的接口,成功返回数据。

  • 相关阅读:
    数据分析(三)
    数据分析(二)
    数据分析(一)
    sql server 脚本创建数据库和表
    各种距离分析
    DataTable数据导出CSV文件
    WPF中Grid布局
    111
    123
    SVN的安装与使用
  • 原文地址:https://www.cnblogs.com/wangcongsuibi/p/10369712.html
Copyright © 2011-2022 走看看