随笔 - 59  文章 - 20  评论 - 61  阅读 - 85494

把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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

在实际项目中,判断用户名和密码可以查询数据库,也可以自定义一些算法,隐藏在用户名和密码之中,达到加密的目的。还可以再加上认证错误就屏蔽该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);
            }

        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

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

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;
            };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这里写图片描述

顺便提一下这个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前途一片光明。

原文链接: https://blog.csdn.net/woodsun2008/article/details/79048633
posted on   SunnyTrudeau  阅读(199)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示