把Web Api OData移植到Asp.Net Core(6)-基本认证

虽然采用了https传输,但是网站的安全性还是不够的,比如,通过浏览器可以访问网站,只要忽略浏览器的警告信息即可。如果是提供网页应用的网站,可以考虑Asp.Net Core提供的各种身份验证措施。但是如果OData网站只是给客户端Api调用的,可以采用简单的基本认证。然而Asp Net Core不像Asp.Net那样提供对基本认证的支持,需要写一个中间件去实现,其实也不难。

1.在网站实现基本认证

添加一个BasicAuthenticationMiddlerware中间件,实现基本认证。

//基本认证中间件
    public sealed class BasicAuthenticationMiddlerware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        public BasicAuthenticationMiddlerware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.CreateLogger<BasicAuthenticationMiddlerware>();
        }

        public async Task InvokeAsync(HttpContext context)
        {
            //基本认证
            bool success = Authorization(context);

            if (success)
            {
                _logger.LogWarning($"{DateTime.Now}, BasicAuthenticationMiddlerware.InvokeAsync, Authorized");

                //如果通过认证,执行下一个环节
                await _next.Invoke(context);
            }
            else
            {
                _logger.LogWarning($"{DateTime.Now}, BasicAuthenticationMiddlerware.InvokeAsync, Unauthorized");

                //如果没通过认证,终止请求
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Response.Headers.Add("WWW-Authenticate", "Basic Scheme='Authentication'");
            }
        }

        //基本认证
        private bool Authorization(HttpContext context)
        {
            try
            {
                //获取认证信息,如果没有返回string.Empty
                string authHeader = context.Request.Headers["Authorization"];

                //没有认证信息
                if (string.IsNullOrWhiteSpace(authHeader))
                    return false;

                //没有基本认证信息
                if (!authHeader.Contains("Basic"))
                    return false;

                //获取用户名和密码Base64字符串
                var userNameAndPasswordBase64Str = authHeader.Trim().Split(" ")[1];

                //获取用户名和密码字符串
                Encoding encoding = Encoding.GetEncoding("iso-8859-1");
                string userNameAndPasswordStr = encoding.GetString(Convert.FromBase64String(userNameAndPasswordBase64Str));

                //获取用户名和密码数组
                string[] userNameAndPasswordAry = userNameAndPasswordStr.Split(':');

                //获取用户名和密码
                string userName = userNameAndPasswordAry[0];
                string password = userNameAndPasswordAry[1];

                //判断用户名和密码
                if ((userName == "admin") && (password == "123"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

    }//BasicAuthenticationMiddlerware

在实际项目中,判断用户名和密码可以查询数据库,也可以自定义一些算法,隐藏在用户名和密码之中,达到加密的目的。还可以再加上认证错误就屏蔽该IP一段时间,防止暴力破解等措施。

在Startup添加使用中间件。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            //一定要添加在app.UseMvc()之前
            app.UseMiddleware<BasicAuthenticationMiddlerware>();

            //支持OData
            var builder = new ODataConventionModelBuilder(app.ApplicationServices);

            builder.EntitySet<Book>("Books");

            app.UseMvc(routeBuilder =>
            {
                routeBuilder.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());

                //允许全部查询操作,替代方法是在实体类上做标注,或者在数据库OnModelCreating时HasAnnotation标注
                routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

                // Work-around for #1175
                routeBuilder.EnableDependencyInjection();
            });

            //初始化数据库
            using (var scope = app.ApplicationServices.CreateScope())
            {
                var context = scope.ServiceProvider.GetRequiredService<BookDbContext>();
                SeedData.SeedDB(context);
            }

        }

再次运行网站,通过浏览器访问网站,会提示要求输入用户名和密码。
这里写图片描述

2.在客户端提供基本认证信息

Simple.OData.Client支持使用基本认证信息访问服务器,只需要设置一下settings.Credentials即可。

private void frmMain_Load(object sender, EventArgs e)
        {
            //允许访问https网站,对http访问无干扰
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

            //初始化OData客户端
            settings = new ODataClientSettings(DataUri);
            settings.PayloadFormat = ODataPayloadFormat.Json;
            settings.RequestTimeout = TimeSpan.FromSeconds(30);

            //创建基本认证消息
            settings.Credentials = new NetworkCredential("admin", "123");

            btnRefresh.Click += async (ss, ee) =>
            {
                var client = new ODataClient(settings);

                var result = await client.For<Book>().FindEntriesAsync();
                var books = result.ToList();

                this.dataGridViewBook.DataSource = books;
            };

这里写图片描述

顺便提一下这个Simple.OData.Client,它也是支持跨平台的,可以用来实现业务类库,然后给PC客户端和安卓、iOS移动客户端调用。Simple.OData.Client目前未支持NetStandard,这点比较遗憾。

至此,OData网站移植到Asp.Net Core,采用docker,部署到Linux服务器,采用MySQL数据库,采用https加密传输和基本认证,全部完成。以前的客户端软件无需更改,可以直接沿用。如果微软能够在后续升级中提供跟以前Asp.Net Web Api 2 OData一样的自动化搭建控制器的功能,就更好了。

小结

一点感受:
学习Asp.Net Core的过程不算长,但是涉及的知识面非常广,主要是跨平台方面的,如Linux、docker等。过去长期在Windows平台呆习惯了,一下子切换到Linux平台,有点不适应,看着Linux的字符界面不知道如何下手,连鼠标都变成废铁了。
但是一旦熟悉了docker那一套玩法,就再也不想回到Windows Server了。最重要的是,Linux不限量免费使用,成本优势太明显了。
Visual Studio是一个效率极高的生产力工具,并且门槛还很低,学习曲线平缓。微软的跨平台战略,使得开发者可以通过一个工具,一门语言,同时开发Linux服务端,PC客户端,安卓和iOS移动客户端,大量共享数据结构和业务类库,极大降低了移动互联网解决方案的开发和运维成本。只有当移动互联网实现成本低到大部分行业和中小企业都能接受的时候,万物互联才能成为现实。从这个角度看,.Net Core前途一片光明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值