• ASP.NET Core2利用Jwt技术在服务端实现对客户端的身份认证


    背景

    在微服务架构下,一般都会按不同的业务或功能将整个系统切分成不同的独立子系统,再通过REST API或RPC进行通讯并相互调用,形成各个子系统之间的串联结构。在这里,我们将采用REST API的通讯方式。

    比如:

    1、有一个“用户中心”独立子系统名为“Lezhima.UserHub”,是一个基于ASP.NET Core mvc 2.0的项目。

    2、有一个处理用户订单的独立子系统名为“Lezhima.UserOrder”,是一个基于ASP.NET Core webp api 2.0的项目。

    3、同时还有一个处理用户文件上传的独立子系统名为“Lezhima.UserUpload”,是一个基于ASP.NET Core webp api 2.0的项目。

    业务关系如下:

    用户成功登录后进入“Lezhima.UserHub”,在用户查看订单时通过前端Ajax调用“Lezhima.UserOrder”的web api接口,在用户上传图片是通过前端Ajax调用“Lezhima.UserUpload”的web api接口。

    至此,我们了解了上面的业务关系后,心里一定产生出如下两个问题:

    1、如何保障“Lezhima.UserOrder”与“Lezhima.UserUpload”两个独立系统内的web api接口安全,因为它们已经被暴露在了前端。

    2、如何在“Lezhima.UserHub”站颁发Token。

    那么,带着问题我们下面就结合ASP.NET Core 自带的Jwt技术来讨论具体的实现(也许聪明的你有更好的解决方法,请一定告知我,谢谢)。

    Jwt 全名为:JSON Web Token,是一个很成熟的技术,园子里也有很多这方面的知识,我这里就不再重述了。

    实现原理

    “Lezhima.UserHub”站因为已经做了登录验证,我们暂且认为它是可信的,所以在前端Ajax请求“Lezhima.UserOrder”站的web api接口时先到自已后端去生成一个Token,并随之同本次跨站请求一块携带至“Lezhima.UserOrder”站,“Lezhima.UserOrder”站验证请求头中的Token是否合法,如合法则继续路由到具体方法中,否则结束请求。“Lezhima.UserUpload”站原理与“Lezhima.UserOrder”相同。

    实现代码

    Lezhima.UserHub颁发Token代码:

            /// <summary>
            /// 颁发一个指定有效期的Token,并将当前登录的用户id传递进来		
            /// </summary>
            /// <param name="currentUserId"></param>
            /// <param name="expiresMinutes"></param>
            /// <returns></returns>
    	  public static async Task<string> GetAccessToken(string currentUserId,int expiresMinutes=2)
            {
                return await Task.Run(() =>
                {
    				//约定私钥,下面三个参数可放到配置文件中				
                    var secret = "NGUzNmNlNzQtZThkZC00YjRh";
    				//发行者
                    var iss = "Andre";
    				//接受者
                    var aud = "Andre";
    
                    if (string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(iss) || string.IsNullOrEmpty(aud))
                        return "";
    
                    if (string.IsNullOrEmpty(currentUserId))
                        currentUserId = Guid.NewGuid().ToString();
    
                    var now = DateTime.UtcNow;
                    var claims = new Claim[]
                    {
                        new Claim(JwtRegisteredClaimNames.Sub, currentUserId),
                        new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)
                    };
                    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret));
                    var jwt = new JwtSecurityToken(
                           issuer: iss,
                           audience: aud,
                           claims: claims,
                           notBefore: now,
                           expires: now.Add(TimeSpan.FromMinutes(expiresMinutes)),
                           signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
                     );
                    return new JwtSecurityTokenHandler().WriteToken(jwt);  //生成一个新的token
                });           
            }
    

    Lezhima.UserHub前端Ajax跨站请求代码:

    //封装一个Ajax请求公共方法
    function GetWebDataByObject(url, requestMethon, paramter) {
        jQuery.support.cors = true;
        apiUrl = 'http://127.0.0.1:8012/';
        var token = GetToken(); //调用本站内的Token颁发Web api接口 
        var result = [];
        $.ajax({
            type: requestMethon,
            url: apiUrl + url,
            data: paramter,
            async: false,
            beforeSend: function (xhr) {
    			//将Token携带到请求头中
                xhr.setRequestHeader("Authorization", "Bearer " + token);
            },  
            success: function (data) {
                result = data;
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                // 状态码
                console.log(XMLHttpRequest.status);
                // 状态
                console.log(XMLHttpRequest.readyState);
                // 错误信息   
                console.log(textStatus);
            }
        });
        return result;
    }
    

    “Lezhima.UserOrder”站开启Jwt的Token验证,在Startup.cs里添加如下代码:

            public IServiceProvider ConfigureServices(IServiceCollection services)
            {            
                services.AddCors();
    			
    			//从配置文件中获取私钥、发行者、接受者三个参数
    			//三个参数的值必需与颁发Token站相同
                var audienceConfig = Configuration.GetSection("Audience");
    
                var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));
                var tokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = signingKey,
                    ValidateIssuer = true,
                    ValidIssuer = audienceConfig["Iss"],
                    ValidateAudience = true,
                    ValidAudience = audienceConfig["Aud"],
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero,
                    RequireExpirationTime = true,
                };
    			//注入Jwt验证
                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                    .AddJwtBearer(options => {
                        options.RequireHttpsMetadata = false;
                        options.TokenValidationParameters = tokenValidationParameters;
                    });
    
                services.AddMvc();
    
    
                var builder = new ContainerBuilder();
                builder.RegisterModule(new Evolution());
                builder.Populate(services);
                var container = builder.Build();
                return container.Resolve<IServiceProvider>();
            }
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                app.UseCors(builder =>
                  builder.WithOrigins("*")
                  .AllowAnyHeader()
                  .AllowAnyMethod()
                  .AllowCredentials()
                );         
                //开启验证
                app.UseAuthentication();
                app.UseMvc();
            }
    

    “Lezhima.UserOrder”站内的控制器里添加验证过滤器[Authorize],如下代码:

        [Route("api/[Controller]")]
        //添加过滤器后,该控制器内所有Action都将进行Token验证
        [Authorize]
        public class OrderController : Controller
        {
            
        }
    

      

    至此,基于ASP.NET Core的Jwt跨站验证Token方案就全部完成了,是不是很简单呀^_^  ^_^ !! 

    总结

    1、Token颁发者与验证者都必需使用相同的私钥,私钥、发行者、接受者等参数可以放在配置文件中动态配置!

    2、在项目Startup类中的ConfigureServices方法内添加注册使用Jwt身份验证的功能。

    3、在验证者项目的控制器上或方法上加上过滤器 [Authorize]即可开启身份验证。

    声明

    本文为作者原创,转载请备注出处与保留原文地址,谢谢。如文章能给您带来帮助,请点下推荐或关注,感谢您的支持!

  • 相关阅读:
    软件测试的定义及分类总结
    Selenium下拉菜单(Select)的操作Selenium快速入门(五)
    Selenium框架切换Selenium快速入门(七)
    元素(WebElement)Selenium快速入门(三)
    Selenium窗口切换Selenium快速入门(六)
    Selenium简介与环境搭配Selenium快速入门(一)
    测试用例的几种常见设计方法
    driver.get()和driver.navigate().to()到底有什么不同?Selenium快速入门(四)
    元素定位Selenium快速入门(二)
    关于VS2010与SQL Server2008 R2的安装问题
  • 原文地址:https://www.cnblogs.com/Miidy/p/9542863.html
Copyright © 2020-2023  润新知