用最清爽的方式開發(fā)dotNet
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
已開源,沒啥技術(shù)含量,只是一個(gè)思路, -> 開源地址前提假設(shè)我要做一個(gè)簡(jiǎn)單的api 方式想到清爽,那肯定是簡(jiǎn)單方便,腦袋第一個(gè)念頭就是.Net6 推出的miniapi了 官方路子兩篇官方文檔足以,按照文檔step by step 就ok了,其他的需要就加 我的野路子官方是官方,官方走的路子當(dāng)然還是基于它最標(biāo)準(zhǔn)的搞法,我的路子則是基于國(guó)內(nèi)實(shí)際情況 模擬前提場(chǎng)景搞一個(gè)普通企業(yè)官網(wǎng)的api,那么要求就是以下幾點(diǎn)
根據(jù)這些要求,我需要引入最基本的就幾個(gè):
如果有其他需求,再自己加,一點(diǎn)也不冗余 注意:需要先右鍵控制臺(tái)項(xiàng)目,將 代碼
var builder = WebApplication.CreateBuilder(args); #region 基本設(shè)置 builder.Services.AddMemoryCache(); builder.Services.AddControllers(); builder.Services.Configure<FormOptions>(options => { // 設(shè)置上傳大小限制256MB options.MultipartBodyLengthLimit = 268435456; }); builder.Services.AddSingleton<SqlSugarMemoryCacheService>(); #endregion #region 授權(quán)鑒權(quán) // 添加身份驗(yàn)證和授權(quán)中間件 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "ningissuer", ValidAudience = "wr", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("sdfsdfsrty45634kkhxxhtdgdfss345t678xx")) }; }); builder.Services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => { policy.RequireClaim("role", "admin"); }); }); #endregion #region swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "企業(yè)官網(wǎng)Api", Version = "v1" }); // 添加身份驗(yàn)證 c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey }); // 添加授權(quán)要求 c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] {} } }); // 設(shè)置 XML 注釋文件的路徑 var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); }); #endregion var app = builder.Build(); app.UseSwagger(); app.UseStaticFiles(); // 啟用身份驗(yàn)證和授權(quán)中間件 app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); // 這里配置了使用控制器的路由 }); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "企業(yè)官網(wǎng)Api"); c.RoutePrefix = string.Empty; // 將 Swagger UI 設(shè)置為應(yīng)用程序的根路徑 }); ServiceLocator.Instance = app.Services; ServiceLocator.ApplicationBuilder = app; var db = SqlSugarHelper.Db; //數(shù)據(jù)庫(kù)初始化 app.MapGet("/seed", async () => { db.CodeFirst.InitTables<SysUserEntity>(); string name = "op"; string pwd = "op"; var loginResult = await db.Queryable<SysUserEntity>().Where(a => !a.IsBan && a.UsePwd == pwd && a.UserName == name).AnyAsync(); if (!loginResult) { await db.Insertable<SysUserEntity>(new SysUserEntity { IsBan = false, UsePwd = pwd, UserName = name }).ExecuteCommandAsync(); } db.CodeFirst.InitTables<FileSourceEntity>(); db.CodeFirst.InitTables<ArticleEntity>(); }); app.MapGet("/health", () => "1024"); app.Run(); 接口就“勉為其難”的新建個(gè)api文件夾然后 /// <summary> /// 系統(tǒng)用戶 /// </summary> [Route("api/[controller]/[action]")] [ApiController] public class SysUserController : BaseApi { public SysUserController() { } /// <summary> /// 檢測(cè)Token信息 /// </summary> /// <returns></returns> [HttpGet] [Authorize] public ApiResult CheckToken() { var httpContext = HttpContext; // 從請(qǐng)求頭中獲取 Authorization 標(biāo)頭的值 var authorizationHeader = httpContext.Request.Headers["Authorization"].FirstOrDefault(); if (!string.IsNullOrEmpty(authorizationHeader) && authorizationHeader.StartsWith("Bearer ")) { // 提取令牌字符串(去除 "Bearer " 前綴) var token = authorizationHeader.Substring(7); var tokenHandler = new JwtSecurityTokenHandler(); var jwtToken = tokenHandler.ReadJwtToken(token); // 獲取 ClaimTypes.Name 的值 var username = jwtToken.Claims.FirstOrDefault(claim => claim.Type == "name")?.Value; // 在這里使用 username 進(jìn)行其他操作 return Success($"當(dāng)前Token用戶是:{username}"); } return Error("Toekn信息解析失敗"); } /// <summary> /// 登錄 /// </summary> /// <param name="model"></param> /// <returns></returns> [AllowAnonymous] [HttpPost] public async Task<ApiResult> Login(SysUserEntity model) { string secretKey = "sdfsdfsrty45634kkhxxhtdgdfss345t678xx"; var loginResult = await db.Queryable<SysUserEntity>().Where(a => !a.IsBan && a.UsePwd == model.UsePwd && a.UserName == model.UserName).AnyAsync(); // 驗(yàn)證用戶名和密碼 if (!loginResult) { return Error("賬號(hào)密碼錯(cuò)誤"); } // 生成 JWT 令牌 var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(secretKey); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new List<Claim> { new Claim(ClaimTypes.Name, model.UserName), new Claim(JwtRegisteredClaimNames.Jti, model.Id.ToString()), new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString()), new Claim(ClaimTypes.Expiration, DateTime.Now.AddHours(10).ToString()) }), Expires = DateTime.UtcNow.AddDays(7), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature), Issuer = "ningissuer", Audience = "wr",
}; var token = tokenHandler.CreateToken(tokenDescriptor); var tokenString = tokenHandler.WriteToken(token); // 返回 JWT 令牌 return Success(new { token = "Bearer " + tokenString }); } } 到這里,基本上已經(jīng)結(jié)束了,剩下的無非加加業(yè)務(wù),或者加一些更豐富的組件,什么autofac啦,nacos啦,yarp啦,seq啦 總結(jié)對(duì)項(xiàng)目而言其實(shí)這種方式已經(jīng)足夠適用絕大多數(shù)中小公司的普通項(xiàng)目需求了,如果你還要加些限流或者什么中間件的話,也是可以很直觀的去加,而不是像某些框架封裝一坨又一坨,你在哪加個(gè)什么東西要翻找半天,毀壞了原本dotNet自身的生態(tài)(指官方文檔) 這樣出來對(duì)的項(xiàng)目也很直觀,物盡其才,只要后續(xù)開發(fā)定好一個(gè)規(guī)范管理,就不會(huì)像你公司那破框架一堆密密麻麻的東西都沒使用過的情況出現(xiàn) 對(duì)新手而言同時(shí)呢,這樣構(gòu)建一個(gè)項(xiàng)目框架,也方便新手學(xué)習(xí),因?yàn)槭值闹庇^,不會(huì)對(duì)莫名其妙出現(xiàn)的東西感覺到匪夷所思,根本不知道拿來做什么的,像這樣需要什么加什么,就對(duì)所有加的東西包括nuget包,中間件,或者封裝啥的都有個(gè)很清晰的認(rèn)知 對(duì)轉(zhuǎn)行到.Net的人而言dotnet官方本身已經(jīng)是一個(gè)大封裝了,不要把別的語(yǔ)言思維帶到這里,做什么破功能都要自己寫,寫又寫不好,寫好了又沒文檔,人走了之后又坑公司又坑其他.net開發(fā)者 結(jié)語(yǔ),給所有中小公司和個(gè)人的開發(fā)建議馬上2024了,.Net的生態(tài)已經(jīng)算是十分豐富了,請(qǐng)不要再試圖自行造輪子 舉個(gè)例子假如你要 別在那自己瞎琢磨封裝,對(duì)個(gè)人而言你瞎封裝有什么用對(duì)你也沒什么好處費(fèi)時(shí)費(fèi)力,還封裝不好,你能保證自己封裝完了還會(huì)提供詳細(xì)的文檔? 一句很重要的話,我在一線開發(fā)從curd干到框架,我覺得很多人都沒意識(shí)到的一點(diǎn)就是: 就剛才這封裝的例子,如果你是自己封裝,隨便有點(diǎn)變動(dòng)你是不是要拋下業(yè)務(wù)需求不管去維護(hù)? 代碼文件補(bǔ)充SqlSugarHelperpublic class SqlSugarHelper { public static readonly SqlSugarScope Db = new SqlSugarScope(new ConnectionConfig() { ConnectionString = "server=xxx;Database=xxx;Uid=root;Pwd=xxx;Port=6607;Allow User Variables=True;",//連接符字串 DbType = DbType.MySql, IsAutoCloseConnection = true, }, db => { ExternalServicesSetting(db); db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine(sql); }; }); /// <summary> /// 拓展配置 /// </summary> /// <param name="db"></param> /// <param name="config"></param> private static void ExternalServicesSetting(SqlSugarClient db) { var cache = ServiceLocator.Instance.GetService<SqlSugarMemoryCacheService>(); db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices { DataInfoCacheService = cache, }; } } 該文章在 2023/12/25 16:05:11 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |