网上很多教程的结果是这样的,用postman获取token,再复制到下图value进行登录,这样的方式感觉有点呆。
理想的状态是跳到登录界面,实现集成登录验证,如图
自动跳转到登录界面
登录后再自动跳转到swgger
实现步骤
1、NuGet包添加Swashbuckle.AspNetCore
?
自定义鉴权中间件SetupAuthenticationMiddleware
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace Kstopa.Extensions.Middlewares
{
public static class SetupAuthenticationMiddleware
{
public static void AddAuthenticationSetup(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.Audience = "KstopaAcs";
options.TokenValidationParameters = new()
{
ValidateAudience = false,
ValidateIssuerSigningKey = true,
ValidateIssuer = false,
LifetimeValidator = (before, expires, token, param) =>
{
return expires > DateTime.UtcNow;
}
};
});
// API授权
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "KstopaAcs");
});
});
}
}
}
?自定义SetupSwaggerGenMiddleware中间件
代码如下(ApiGroup与DescriptionAttribute类不建议到中间件里,ApiGroup是定义的分组)
关键代码:Flows使用Implicit类型,不要使用AuthorizationCode)
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace Kstopa.Extensions.Middlewares
{
public static class SetupSwaggerGenMiddleware
{
public static IServiceCollection AddSwaggerGenSetup(this IServiceCollection services, Action<SwaggerGenOptions> setupAction = null)
{
return services.AddSwaggerGen(delegate (SwaggerGenOptions options)
{
Func<OpenApiSchema> schemaFactory = () => new OpenApiSchema
{
Type = "string",
Format = "binary"
};
setupAction?.Invoke(options);
});
}
public static IServiceCollection AddSwaggerGenWithOAuthSetup(this IServiceCollection services, string authority,
Dictionary<string, string> scopes, Action<SwaggerGenOptions> setupAction = null)
{
return services.AddSwaggerGenSetup().AddSwaggerGen(delegate (SwaggerGenOptions options)
{
options.OperationFilter<SecurityRequirementsOperationFilter>();
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(authority + "connect/authorize"),
Scopes = scopes,
TokenUrl = new Uri(authority + "connect/token")
}
}
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
Array.Empty<string>()
}
});
setupAction?.Invoke(options);
});
}
/// <summary>
/// 添加Xml注释
/// </summary>
/// <param name="options"></param>
public static void AddXmlComments(this SwaggerGenOptions options)
{
var basePath = AppContext.BaseDirectory;
#region Controller的注释
{
var xmlPath = Path.Combine(basePath, "Kstopa.HttpApi.Host.xml");
if (File.Exists(xmlPath))
{
options.IncludeXmlComments(xmlPath, true);//第二参数要设为true,默认为false
}
}
#endregion
#region Model的注释
{
var xmlModelPath = Path.Combine(basePath, "Kstopa.Model.xml");
if (File.Exists(xmlModelPath))
{
options.IncludeXmlComments(xmlModelPath);//第二参数默认为false,不用设
options.CustomSchemaIds(type => type.ToString());
}
}
#endregion
}
/// <summary>
/// 按模块分组
/// </summary>
/// <param name="options"></param>
public static void GroupByModule(this SwaggerGenOptions options)
{
#region 按模块分组显示
{
var fields = typeof(ApiGroup).GetFields().ToList();
fields.ForEach(f =>
{
var info = f.GetCustomAttributes(typeof(DescriptionAttribute), false)
.OfType<DescriptionAttribute>()
.FirstOrDefault();
options.SwaggerDoc($"{f.Name}", new OpenApiInfo
{
Title = $"{info?.Title} 接口文档-{RuntimeInformation.FrameworkDescription}",
Version = $"{info?.Version}",
Description = $"版本:{info?.Version} <br>{info?.Remark}"
});
options.OrderActionsBy(o => o.RelativePath);
});
}
#endregion
#region 无分组归类显示
{
options.SwaggerDoc("无分组", new OpenApiInfo
{
Title = $"接口文档——{RuntimeInformation.FrameworkDescription}",
Version = "v1",
Description = "Kstopa MES HTTP API v1"
});
options.DocInclusionPredicate((docName, description) =>
{
if (docName.Equals("NoGroup"))
{
return string.IsNullOrEmpty(description.GroupName);
}
return description.GroupName == docName;
});
}
#endregion
}
}
public class ApiGroup
{
[Description(Title = "系统通用", Remark = "导入(出)、定时任务、缓存、消息队列")]
public static string Common_v1;
[Description(Title = "系统框架", Remark = "组织、部门、用户、角色、权限、登录、枚举")]
public static string Framework_v1;
}
public class DescriptionAttribute : Attribute
{
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 版本
/// </summary>
public string Version { get; set; } = "v1";
}
}
?在Program.cs使用中间件
#region Authentication 鉴权设置
{
builder.Services.AddAuthenticationSetup(builder.Configuration);
IdentityModelEventSource.ShowPII = true;//解决IDX10214: Audience validation failed. Audiences: '[PII is hidden]'错误
builder.Services.AddHttpContextAccessorSetup();
}
#endregion
builder.Services.AddCorsSetup(builder.Configuration);//跨域配置
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGenWithOAuthSetup(
builder.Configuration["AuthServer:Authority"],
new Dictionary<string, string>
{
{"KstopaAcs", "KstopaAcs API"}
},
options =>
{
options.GroupByModule();
options.AddXmlComments();
options.CustomSchemaIds(type => type.FullName);
});
配置文件代码
?"App": { ? ? "CorsOrigins": "https://*.KstopaAcs.com", ? ? "RegisterModule": "Kstopa.Service.dll", ? ? "StaticFilePath": "doc" ? }, ? "AuthServer": { ? ? "Authority": "https://192.168.18.13:9081/", ? ? "RequireHttpsMetadata": false, ? ? "SwaggerClientId": "Kstopa", ? ? "SwaggerClientSecret": "xxxx" ? }
如下图
?
IdentityServer配置
RedirectUris为api服务地址+swagger/oauth2-redirect.html,如下图
可能会遇到的问题如下:
本机调试和服务器同时使用,只要在IdentityServer配置文件中添加多个RedirectUris即可
?跳到在登录界面录入帐号和密码后不跳转,必须使用https才可以,https需要证书请参考这里
使用 mkcert 解决 局域网IIS 网页 SSL 证书问题 - googlegis - 博客园
安装证书后,浏览器的安全锁如下图是正常的(客户端和服务器都要安装crt证书,按上图链接操作
?如果前端请求提示:IDX20803,一般是证书导致的问题(服务器没有安装证书)
证书加载代码:
var cert = new X509Certificate2(builder.Configuration["cert:path"], builder.Configuration["cert:password"]);
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.ConfigureHttpsDefaults(c =>
{
c.ServerCertificate = cert;
});
}
?
如果有问题请加微信讨论:25489181
?
?
?
?
|