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確認了請求者的身份,現在放行請求讓他訪問我們的接口,成功返回數據。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM