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确认了请求者的身份,现在放行请求让他访问我们的接口,成功返回数据。

  • 相关阅读:
    A1066 Root of AVL Tree (25 分)
    A1099 Build A Binary Search Tree (30 分)
    A1043 Is It a Binary Search Tree (25 分) ——PA, 24/25, 先记录思路
    A1079; A1090; A1004:一般树遍历
    A1053 Path of Equal Weight (30 分)
    A1086 Tree Traversals Again (25 分)
    A1020 Tree Traversals (25 分)
    A1091 Acute Stroke (30 分)
    A1103 Integer Factorization (30 分)
    A1032 Sharing (25 分)
  • 原文地址:https://www.cnblogs.com/wangcongsuibi/p/10369712.html
Copyright © 2011-2022 走看看