From 8cfef9cd3a732c545d56c7d82de9eb9d98d1a0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E7=9F=B3=E5=A4=B4?= Date: Sun, 3 Nov 2024 01:03:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Swagger=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84OAuth2.0=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CubeDemo/CubeDemo.csproj | 4 +-- .../SwaggerConfigureOptions.cs | 8 +++-- NewLife.Cube.Swagger/SwaggerService.cs | 22 ++++++++++---- .../Areas/Admin/AdminAreaRegistration.cs | 2 +- NewLife.Cube/Controllers/CubeController.cs | 2 +- NewLife.Cube/Controllers/SsoController.cs | 7 ++++- NewLife.Cube/Web/Models/SsoTokenModel.cs | 30 ++++++++----------- NewLife.CubeNC/Controllers/SsoController.cs | 10 +++++++ 8 files changed, 56 insertions(+), 29 deletions(-) diff --git a/CubeDemo/CubeDemo.csproj b/CubeDemo/CubeDemo.csproj index f5481577c..fb5c322be 100644 --- a/CubeDemo/CubeDemo.csproj +++ b/CubeDemo/CubeDemo.csproj @@ -5,8 +5,8 @@ 魔方WebApi 魔方前后端分离版本的后端WebApi 新生命开发团队 - ©2002-2023 NewLife - 5.5 + ©2002-2024 NewLife + 6.1 $([System.DateTime]::Now.ToString(`yyyy.MMdd`)) $(VersionPrefix).$(VersionSuffix) $(Version) diff --git a/NewLife.Cube.Swagger/SwaggerConfigureOptions.cs b/NewLife.Cube.Swagger/SwaggerConfigureOptions.cs index f147288b8..ed9e1bed1 100644 --- a/NewLife.Cube.Swagger/SwaggerConfigureOptions.cs +++ b/NewLife.Cube.Swagger/SwaggerConfigureOptions.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; +using NewLife.Reflection; using Swashbuckle.AspNetCore.SwaggerGen; namespace NewLife.Cube.Swagger; @@ -34,10 +35,13 @@ public void Configure(SwaggerGenOptions options) var area = controller.ControllerTypeInfo.GetCustomAttribute(); if (area != null) { + var type = area.GetType(); + var asm = AssemblyX.Create(type.Assembly); info = new OpenApiInfo { - Title = area.GetType().GetDisplayName(), - Description = area.GetType().GetDescription()?.Replace("\n", "
") + Title = type.GetDisplayName(), + Description = type.GetDescription()?.Replace("\n", "
"), + Version = asm.FileVersion, }; break; } diff --git a/NewLife.Cube.Swagger/SwaggerService.cs b/NewLife.Cube.Swagger/SwaggerService.cs index 2ea9dd628..05ba76a56 100644 --- a/NewLife.Cube.Swagger/SwaggerService.cs +++ b/NewLife.Cube.Swagger/SwaggerService.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using NewLife.Cube.Entity; +using NewLife.Reflection; using Swashbuckle.AspNetCore.SwaggerGen; namespace NewLife.Cube.Swagger; @@ -26,7 +27,8 @@ public static IServiceCollection AddCubeSwagger(this IServiceCollection services var xml = "NewLife.Cube.xml".GetFullPath(); if (File.Exists(xml)) options.IncludeXmlComments(xml, true); - options.SwaggerDoc("v1", new OpenApiInfo { Title = "第三代魔方", Description = "第三代魔方WebApi接口,用于前后端分离。" }); + var asm = AssemblyX.Entry; + options.SwaggerDoc("v1", new OpenApiInfo { Title = "第三代魔方", Description = "第三代魔方WebApi接口,用于前后端分离。", Version = asm.FileVersion }); //options.SwaggerDoc("Basic", new OpenApiInfo { Version = "basic", Title = "基础模块" }); //options.SwaggerDoc("Admin", new OpenApiInfo { Version = "admin", Title = "系统管理" }); //options.SwaggerDoc("Cube", new OpenApiInfo { Version = "cube", Title = "魔方管理" }); @@ -48,8 +50,8 @@ public static IServiceCollection AddCubeSwagger(this IServiceCollection services var cfg = oauthConfigs[0]; var flow = new OpenApiOAuthFlow { - AuthorizationUrl = new Uri(cfg.Server), - TokenUrl = new Uri(!cfg.AccessServer.IsNullOrEmpty() ? cfg.AccessServer : cfg.Server), + AuthorizationUrl = new Uri(cfg.Server + "/authorize"), + TokenUrl = new Uri((!cfg.AccessServer.IsNullOrEmpty() ? cfg.AccessServer : cfg.Server) + "/access_token"), //Scopes = new Dictionary //{ // { "api1", "Access to API #1" } @@ -58,10 +60,17 @@ public static IServiceCollection AddCubeSwagger(this IServiceCollection services options.AddSecurityDefinition("OAuth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, + In = ParameterLocation.Query, Flows = new OpenApiOAuthFlows { AuthorizationCode = flow } }); - //options.OperationFilter(); + // 声明一个Scheme,注意下面的Id要和上面AddSecurityDefinition中的参数name一致 + var scheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "OAuth2" } + }; + // 注册全局认证(所有的接口都可以使用认证) + options.AddSecurityRequirement(new OpenApiSecurityRequirement() { [scheme] = [] }); } else { @@ -72,7 +81,7 @@ public static IServiceCollection AddCubeSwagger(this IServiceCollection services Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, - Scheme = "bearer" + Scheme = "Bearer" }); // 声明一个Scheme,注意下面的Id要和上面AddSecurityDefinition中的参数name一致 var scheme = new OpenApiSecurityScheme() @@ -96,6 +105,9 @@ public static IApplicationBuilder UseCubeSwagger(this IApplicationBuilder app) //app.UseSwaggerUI(); app.UseSwaggerUI(options => { + var asm = AssemblyX.Entry; + options.DocumentTitle = !asm.Title.IsNullOrEmpty() ? asm.Title : "魔方Web开发平台"; + //options.SwaggerEndpoint("/swagger/Basic/swagger.json", "Basic"); //options.SwaggerEndpoint("/swagger/Admin/swagger.json", "Admin"); //options.SwaggerEndpoint("/swagger/Cube/swagger.json", "Cube"); diff --git a/NewLife.Cube/Areas/Admin/AdminAreaRegistration.cs b/NewLife.Cube/Areas/Admin/AdminAreaRegistration.cs index 54d1e073c..555157a46 100644 --- a/NewLife.Cube/Areas/Admin/AdminAreaRegistration.cs +++ b/NewLife.Cube/Areas/Admin/AdminAreaRegistration.cs @@ -5,7 +5,7 @@ namespace NewLife.Cube.Areas.Admin; /// 权限管理区域注册 [DisplayName("系统管理")] [Description(""" - 核心功能:用户、角色、菜单,构成基本权限体系。 + 核心功能:用户、角色、菜单,构成基本权限体系。 核心配置:基本设置、系统设置、魔方设置、数据中间件。 OAuth功能:OAuth配置微信钉钉等多个第三方SSO登录。 安全功能:审计日志、访问规则,保障系统安全。 diff --git a/NewLife.Cube/Controllers/CubeController.cs b/NewLife.Cube/Controllers/CubeController.cs index b9c04d873..3f66905ef 100644 --- a/NewLife.Cube/Controllers/CubeController.cs +++ b/NewLife.Cube/Controllers/CubeController.cs @@ -21,7 +21,7 @@ namespace NewLife.Cube.Controllers; [Description(""" 魔方向前端控件提供的一些常用接口,例如用户查询与头像获取等。 """)] -[ApiExplorerSettings(GroupName = "Basic")] +//[ApiExplorerSettings(GroupName = "Cube")] [Route("[controller]/[action]")] public class CubeController : ControllerBaseX { diff --git a/NewLife.Cube/Controllers/SsoController.cs b/NewLife.Cube/Controllers/SsoController.cs index c65f8426f..c143e1213 100644 --- a/NewLife.Cube/Controllers/SsoController.cs +++ b/NewLife.Cube/Controllers/SsoController.cs @@ -53,7 +53,7 @@ namespace NewLife.Cube.Controllers; 魔方支持接入微信钉钉等多个第三方OAuth2.0服务。 魔方自身也可以作为OAuth2.0服务端,支持密码式、凭证式、刷新令牌等多种授权模式。 """)] -[ApiExplorerSettings(GroupName = "Basic")] +//[ApiExplorerSettings(GroupName = "Cube")] [Route("[controller]/[action]")] public class SsoController : ControllerBaseX { @@ -479,6 +479,7 @@ public virtual ActionResult Auth2(String id) /// [AllowAnonymous] [HttpGet] + [HttpPost] public virtual ActionResult Access_Token(String client_id, String client_secret, String code, String grant_type = null) { if (client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(client_id)); @@ -534,6 +535,7 @@ public virtual ActionResult Access_Token(String client_id, String client_secret, /// [AllowAnonymous] [HttpGet] + [HttpPost] public new virtual ActionResult Token(String client_id, String client_secret, String username, String password, String refresh_token, String grant_type = null) { if (client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(client_id)); @@ -600,6 +602,7 @@ public virtual ActionResult Access_Token(String client_id, String client_secret, /// [AllowAnonymous] [HttpGet] + [HttpPost] public virtual ActionResult PasswordToken([FromBody] SsoTokenModel model) { if (model.client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(model.client_id)); @@ -689,6 +692,7 @@ public virtual ActionResult UserInfo(String access_token) /// [AllowAnonymous] [HttpGet] + [HttpPost] public virtual ActionResult Refresh_Token(String client_id, String grant_type, String refresh_token) { if (client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(client_id)); @@ -810,6 +814,7 @@ public ActionResult Verify(String access_token, String redirect_uri) /// [AllowAnonymous] [HttpGet] + [HttpPost] public virtual ActionResult UserAuth([FromBody] SsoTokenModel model) { var client_id = model.client_id; diff --git a/NewLife.Cube/Web/Models/SsoTokenModel.cs b/NewLife.Cube/Web/Models/SsoTokenModel.cs index 774e3ddc3..0fe7aebeb 100644 --- a/NewLife.Cube/Web/Models/SsoTokenModel.cs +++ b/NewLife.Cube/Web/Models/SsoTokenModel.cs @@ -1,24 +1,20 @@ -using System; -using System.Runtime.Serialization; +namespace NewLife.Cube.Web.Models; -namespace NewLife.Cube.Web.Models +/// Sso令牌模型 +public class SsoTokenModel { - /// Sso令牌模型 - public class SsoTokenModel - { - /// 应用标识 - public String client_id { get; set; } + /// 应用标识 + public String client_id { get; set; } - /// 应用密钥 - public String client_secret { get; set; } + /// 应用密钥 + public String client_secret { get; set; } - /// 用户名。可以是设备编码等唯一使用者标识 - public String UserName { get; set; } + /// 用户名。可以是设备编码等唯一使用者标识 + public String UserName { get; set; } - /// 密码 - public String Password { get; set; } + /// 密码 + public String Password { get; set; } - /// 授权类型 - public String grant_type { get; set; } - } + /// 授权类型 + public String grant_type { get; set; } } \ No newline at end of file diff --git a/NewLife.CubeNC/Controllers/SsoController.cs b/NewLife.CubeNC/Controllers/SsoController.cs index c7b52481a..bd16dca33 100644 --- a/NewLife.CubeNC/Controllers/SsoController.cs +++ b/NewLife.CubeNC/Controllers/SsoController.cs @@ -476,6 +476,8 @@ public virtual ActionResult Auth2(String id) /// 授权类型 /// [AllowAnonymous] + [HttpGet] + [HttpPost] public virtual ActionResult Access_Token(String client_id, String client_secret, String code, String grant_type = null) { if (client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(client_id)); @@ -530,6 +532,8 @@ public virtual ActionResult Access_Token(String client_id, String client_secret, /// 授权类型 /// [AllowAnonymous] + [HttpGet] + [HttpPost] public virtual ActionResult Token(String client_id, String client_secret, String username, String password, String refresh_token, String grant_type = null) { if (client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(client_id)); @@ -595,6 +599,8 @@ public virtual ActionResult Token(String client_id, String client_secret, String /// 请求模型 /// [AllowAnonymous] + [HttpGet] + [HttpPost] public virtual ActionResult PasswordToken([FromBody] SsoTokenModel model) { if (model.client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(model.client_id)); @@ -682,6 +688,8 @@ public virtual ActionResult UserInfo(String access_token) /// 刷新令牌 /// [AllowAnonymous] + [HttpGet] + [HttpPost] public virtual ActionResult Refresh_Token(String client_id, String grant_type, String refresh_token) { if (client_id.IsNullOrEmpty()) throw new ArgumentNullException(nameof(client_id)); @@ -799,6 +807,8 @@ public ActionResult Verify(String access_token, String redirect_uri) /// 令牌模型 /// [AllowAnonymous] + [HttpGet] + [HttpPost] public virtual ActionResult UserAuth([FromBody] SsoTokenModel model) { var client_id = model.client_id;