net core3.1打造webapi开发框架的实践

https://www.cnblogs.com/datacool/p/datacool_dotnetcore_demo.html

实践技术看点

  • 1、Swagger管理API说明文档
  • 2、JwtBearer token验证
  • 3、Swagger UI增加Authentication
  • 4、EntityFrameworkCore+MySQL
  • 5、在.net core 3.1下使用Log4net

前言

元旦过后就没什么工作上的任务了,这当然不能让领导看在眼里,动手实践一下新技术吧。于是准备搭一个webapi的中间件框架。

由于自己的云主机是台linux服务器,双核2G的centos+1M 没有数据盘,也用不起RDS,如果装个Windows Server那么肯定卡的不行,所以一直想尝试一下跨平台的感觉。

由于这篇随笔不是定位于教程,故基础知识一概略过。

项目中使用到的包清单

 <ItemGroup>
    <PackageReference Include="IdentityModel" Version="4.1.1" />
    <PackageReference Include="log4net" Version="2.0.8" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.1" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.0" />
    <PackageReference Include="MySql.Data.EntityFrameworkCore" Version="8.0.19" />
    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.0" />
    <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="5.0.0" />
    <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.0.0" />
    <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.0.0" />
  </ItemGroup>

关键代码点评

1)Startup

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using IdentityModel;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using MySql.Data.EntityFrameworkCore.Extensions;
using Swashbuckle.AspNetCore.Swagger;
using tokendemo.Models;

namespace tokendemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.Configure<TokenManagement>(Configuration.GetSection("tokenManagement"));
            var token = Configuration.GetSection("tokenManagement").Get<TokenManagement>();
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.Secret)),
                    ValidIssuer = token.Issuer,
                    ValidAudience = token.Audience,
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1",
                    new OpenApiInfo
                    {
                        Title = "XXX项目接口文档",
                        Version = "v1",
                        Contact = new OpenApiContact
                        {
                            Email = "[email protected]",
                            Name = "肖远峰",
                            Url = new Uri("http://datacool.cnblogs.com")
                        }
                    });
                // 为 Swagger 设置xml文档注释路径
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
                c.AddSecurityDefinition("Bearer",
                    new OpenApiSecurityScheme
                    {
                        Description = "请输入OAuth接口返回的Token,前置Bearer。示例:Bearer {Roken}",
                        Name = "Authorization",
                        In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                        Type = SecuritySchemeType.ApiKey
                    });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                   {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference()
                            {
                                Id = "Bearer",
                                Type = ReferenceType.SecurityScheme
                            }
                        }, Array.Empty<string>()
                    }
                });
            });
            var posdbConnString = Configuration.GetConnectionString("POS_Db");
            services.AddDbContext<posdbContext>(option =>
            {
                option.UseMySql(posdbConnString, null);
            });
            services.AddScoped<IAuthenticateService, TokenAuthenticationService>();
            services.AddScoped<IUserService, UserService>();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
            app.UseSwagger();
            //启用中间件服务生成SwaggerUI,指定Swagger JSON终结点
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "XXX接口文档 V1");
                c.RoutePrefix = string.Empty;//设置根节点访问
            });
            app.UseLog4net();
        }
    }
}

using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace tokendemo
{
    public static class LoggeServiceExt
    {

        /// 使用log4net配置
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseLog4net(this IApplicationBuilder app)
        {
            var logRepository = log4net.LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
            log4net.Config.XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));
            return app;
        }
    }
}

public interface IUserService
    {
        bool IsValid(LoginRequestDTO req);
    }

 public interface IAuthenticateService
    {
        bool IsAuthenticated(LoginRequestDTO request, out string token);
    }

public class UserService : IUserService
    {
        public bool IsValid(LoginRequestDTO req)
        {
            return true;
        }
    }

 public class TokenAuthenticationService : IAuthenticateService
    {
        private readonly IUserService _userService;
        private readonly TokenManagement _tokenManagement;
        private readonly posdbContext db;
        public TokenAuthenticationService(IUserService userService, IOptions<TokenManagement> tokenManagement, posdbContext posdb)
        {
            _userService = userService;
            _tokenManagement = tokenManagement.Value;
            db = posdb;
        }

        public string GetAuthentUser()
        {
            return JsonConvert.SerializeObject(db.SysApiAuthorize.ToList());
        }

        public bool IsAuthenticated(LoginRequestDTO request, out string token)
        {
            token = string.Empty;
            if (!_userService.IsValid(request))
                return false;
            var claims = new[]
            {
               new Claim(ClaimTypes.Name,request.Username)
            };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenManagement.Secret));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwtToken = new JwtSecurityToken(_tokenManagement.Issuer, _tokenManagement.Audience, claims, expires: DateTime.Now.AddMinutes(_tokenManagement.AccessExpiration), signingCredentials: credentials);

            token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
            return true;
        }
    }

token验证是我关注的重点,而Swagger支持查看文档的同时调用API,也支持授权认证,所以水到渠成。代码命名都是比较规范的,当然大部分来源于别人的文章,这里就不作过多说明了。

asp.net core对依赖注入思想是贯彻始终的,新人需要在这个思想的领悟上下苦功夫才能驾驭她。

2)配置文件

 appsettings

 log4net.config

Scaffold-DbContext "server=localhost;userid=root;pwd=dba#2020;port=3306;database=posdb;sslmode=none;" Pomelo.EntityFrameworkCore.MySql -OutputDir Models -Force

由于我的数据库是先存在了,所以直接使用了nutget控制台生成了数据库上下文对象和实体。注意向导生成的数据库上下文里是把数据库连接字符串写死的,需要修改。本例是写入appsettings.json里的。请重点看一下上面的配置和Startup里获取配置的代码。

3)关联代码,几个数据传输类

public class TokenManagement
    {
        [JsonProperty("secret")]
        public string Secret { get; set; }

        [JsonProperty("issuer")]
        public string Issuer { get; set; }

        [JsonProperty("audience")]
        public string Audience { get; set; }

        [JsonProperty("accessExpiration")]
        public int AccessExpiration { get; set; }

        [JsonProperty("refreshExpiration")]
        public int RefreshExpiration { get; set; }
    }

public class WeatherForecast
    {
        public DateTime Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string Summary { get; set; }
    }

 public class LoginRequestDTO
    {
        [Required]
        [JsonProperty("username")]
        public string Username { get; set; }

        [Required]
        [JsonProperty("password")]
        public string Password { get; set; }
    }

3)API控制器

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using log4net;
 6 using Microsoft.AspNetCore.Authorization;
 7 using Microsoft.AspNetCore.Mvc;
 8
 9 namespace tokendemo.Controllers
10 {
11     [ApiController]
12     [Route("[controller]")]
13     [Authorize]
14     public class WeatherForecastController : ControllerBase
15     {
16         private readonly ILog _logger;
17         public WeatherForecastController()
18         {
19             _logger = LogManager.GetLogger(typeof(WeatherForecastController));
20         }
21         private static readonly string[] Summaries = new[]
22         {
23             "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
24         };
25
26
27         [HttpGet]
28         public IEnumerable<WeatherForecast> Get()
29         {
30             var rng = new Random();
31             _logger.Info("OK");
32             return Enumerable.Range(1, 5).Select(index => new WeatherForecast
33             {
34                 Date = DateTime.Now.AddDays(index),
35                 TemperatureC = rng.Next(-20, 55),
36                 Summary = Summaries[rng.Next(Summaries.Length)]
37             })
38             .ToArray();
39         }
40
41     }
42 }

这个大家应该很熟悉了,这就是vs2019向导创建的API控制器。[Authorize]标记会导致401错误,就是表示先要去获取access token,在Header里带入Bearer+空格+token才可以正常调用。

授权控制器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace tokendemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthenticationController : ControllerBase
    {
        private readonly IAuthenticateService _authService;
        public AuthenticationController(IAuthenticateService service)
        {
            _authService = service;
        }

        [AllowAnonymous]
        [HttpPost, Route("requestToken")]
        public ActionResult RequestToken([FromBody] LoginRequestDTO request)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest("Invalid Request");
            }
            string token;
            var authTime = DateTime.UtcNow;
            if (_authService.IsAuthenticated(request, out token))
            {
                return Ok(new
                {
                    access_token = token,
                    token_type = "Bearer",
                    profile = new
                    {
                        sid = request.Username,
                        auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds()
                    }
                });
            }
            return BadRequest("Invalid Request");
        }
    }
}

收获与感想

  • 1、妥妥的吃了次螃蟹,收获了经验
  • 2、正在“为自己挖一口井”的路上
  • 3、.net core算是入门了
  • 4、源码我是没自信放到github的,后面会加上下载链接
  • 5、伙计们分享起来吧,这个生态建设任重而道远啊。

这里是源码下载的地址:https://files.cnblogs.com/files/datacool/tokendemo.zip

原文地址:https://www.cnblogs.com/Leo_wl/p/12441920.html

时间: 2024-10-12 00:30:57

net core3.1打造webapi开发框架的实践的相关文章

使用OAuth打造webapi认证服务供自己的客户端使用(转)

转自:http://www.cnblogs.com/richieyang/p/4918819.html#!comments 一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.注意是Authorization(授权),而不是Authentication(认证).用来做Authentication(认证)的标准叫做openid connect,我们将在以后的文章中进行介绍. 二.名词定义 理解OAuth中的专业术语能够帮助你理解其流程模

一个快速、完善的Android开发框架整合实践(QuickAndroid)

https://github.com/alafighting/QuickAndroid QuickAndroid 一个快速.完善的Android开发框架整合实践 QA项目简介 本框架QuickAndroid(以下简称:QA)尚处于开发阶段. 本项目的宗旨是:整合一个快速.完善的Android开发框架. 编译工具使用:Eclipse + ADT + Android SDK: 编译环境是Android 5.0(21),最低支持Android 2.2(8): 项目编码采用:UTF-8,源码带有中文注释

使用OAuth打造webapi认证服务供自己的客户端使用(二)

在上一篇”使用OAuth打造webapi认证服务供自己的客户端使用“的文章中我们实现了一个采用了OAuth流程3-密码模式(resource owner password credentials)的WebApi服务端.今天我们来实现一个js+html版本的客户端. 一.angular客户端 angular版本的客户端代码来自于http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-

OAuth打造webapi认证服务

使用OAuth打造webapi认证服务供自己的客户端使用 一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.注意是Authorization(授权),而不是Authentication(认证).用来做Authentication(认证)的标准叫做openid connect,我们将在以后的文章中进行介绍. 二.名词定义 理解OAuth中的专业术语能够帮助你理解其流程模式,OAuth中常用的名词术语有4个,为了便于理解这些术语,我们先

使用OAuth打造webapi认证服务供自己的客户端使用

一.什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.注意是Authorization(授权),而不是Authentication(认证).用来做Authentication(认证)的标准叫做openid connect,我们将在以后的文章中进行介绍. 二.名词定义 理解OAuth中的专业术语能够帮助你理解其流程模式,OAuth中常用的名词术语有4个,为了便于理解这些术语,我们先假设一个很常见的授权场景: 你访问了一个日志网站(thir

WebAPI接口开发实践

背景 在团队两年多陆续负责了几个项目的开发上线已经代码的review,特别是对老项目的重构过程中,发现之前的API设计是没有任何规范和约定的,不同的开发同学有不同的习惯,因此需要一套规范去约定,现在分享一下我们目前试运行的一套规范,一起交流完善下. WebAPI开发流程 第一步首先设计接口文档,公司内部有一套自研的多人协作文档系统,可以很好的做到这一步,并能很好的做好版本控制.如果公司内部没有可以基于showdoc搭建一套 第二步有技术负责人确认接口以及字段的命名规范 第三步找对应API对接人,

2017全球 C++ 及系统软件技术大会:一场大师智慧+实践干货的技术盛宴!

从1985年由Bjarne Stroustrup在贝尔实验室发明以来 ,C++作为一门系统级语言,早已超越一门编程语言的影响.由其构建的庞大的系统级软件,已经成为当今世界IT与互联网应用的关键支撑.秉承"全球专家.连接智慧"的理念,我们特邀众多C++和系统软件领域的海内外技术领袖与一线工程实战专家,于2017年11月17日-18日在北京举办"全球C++及系统软件技术大会".大会通过主题演讲.互动研讨.案例分享.高端培训等形式,深度探讨围绕C++及系统软件整个技术栈的

20165101刘天野 2018-2019-2《网络对抗技术》Exp3 免杀原理与实践

20165101刘天野 2018-2019-2<网络对抗技术>Exp3 免杀原理与实践 1. 实践内容 1.1 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧 1.1.1 使用msf编码器 输入命令msfvenom -h可查看相关用法: 编码一次命令如下(用-e参数编码 用-b参数去除坏字符'\00'): msfvenom -p windows/meterpreter/reverse_tcp -e x8

wesome-android

awesome-android Introduction android libs from github System requirements Android Notice If the lib is no longer being maintained,please do not add it here. How To Contribute Step 1. Add a Item as follows: **Library Name**[one space]Short Description