首页 > Windows开发 > 详细

WebApi程序,关于请求的身份验证问题

时间:2019-02-13 15:02:05      阅读:324      评论:0      收藏:0      [点我收藏+]

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

技术分享图片

 

WebApi程序,关于请求的身份验证问题

原文:https://www.cnblogs.com/wangcongsuibi/p/10369712.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!