Browse Source

初始化

master
曹鹏飞 10 months ago
commit
fd676201ec
  1. 3
      .gitignore
  2. 49
      HuiXin.Gateway.Ocelot/Authorizers/HttpRolesAuthorizer.cs
  3. 9
      HuiXin.Gateway.Ocelot/Authorizers/IRolesAuthorizer.cs
  4. 24
      HuiXin.Gateway.Ocelot/Authorizers/RolesAuthorizerBase.cs
  5. 6
      HuiXin.Gateway.Ocelot/Configs/jwt.json
  6. 54
      HuiXin.Gateway.Ocelot/Configs/ocelot.json
  7. 15
      HuiXin.Gateway.Ocelot/Configs/serilog.json
  8. 9
      HuiXin.Gateway.Ocelot/Configurations/RolesAuthorizerConfiguration.cs
  9. 46
      HuiXin.Gateway.Ocelot/Extensions/JWTExtensions.cs
  10. 64
      HuiXin.Gateway.Ocelot/Extensions/OcelotExtensions.cs
  11. 23
      HuiXin.Gateway.Ocelot/HuiXin.Gateway.Ocelot.csproj
  12. 64
      HuiXin.Gateway.Ocelot/JWTUtil.cs
  13. 132
      HuiXin.Gateway.Ocelot/Middlewares/AccessLoggingMiddleware.cs
  14. 34
      HuiXin.Gateway.Ocelot/Middlewares/MyAuthorizationMiddleware.cs
  15. 78
      HuiXin.Gateway.Ocelot/Program.cs
  16. 30
      HuiXin.Gateway.Ocelot/Properties/launchSettings.json
  17. 9
      HuiXin.Gateway.Ocelot/appsettings.Development.json
  18. 9
      HuiXin.Gateway.Ocelot/appsettings.json
  19. 13
      HuiXin.Gateway.Yarp/HuiXin.Gateway.Yarp.csproj
  20. 15
      HuiXin.Gateway.Yarp/Program.cs
  21. 29
      HuiXin.Gateway.Yarp/Properties/launchSettings.json
  22. 8
      HuiXin.Gateway.Yarp/appsettings.Development.json
  23. 9
      HuiXin.Gateway.Yarp/appsettings.json
  24. 37
      HuiXin.Gateway.sln
  25. 12
      HuiXin.Identity.OpenIddict/ApplicationDbContext.cs
  26. 357
      HuiXin.Identity.OpenIddict/Controllers/AuthorizationController.cs
  27. 21
      HuiXin.Identity.OpenIddict/Controllers/UserController.cs
  28. 19
      HuiXin.Identity.OpenIddict/HuiXin.Identity.OpenIddict.csproj
  29. 108
      HuiXin.Identity.OpenIddict/Program.cs
  30. 29
      HuiXin.Identity.OpenIddict/Properties/launchSettings.json
  31. 11
      HuiXin.Identity.OpenIddict/UserInfo.cs
  32. 41
      HuiXin.Identity.OpenIddict/Worker.cs
  33. 8
      HuiXin.Identity.OpenIddict/appsettings.Development.json
  34. 9
      HuiXin.Identity.OpenIddict/appsettings.json

3
.gitignore

@ -0,0 +1,3 @@
.vs
bin
obj

49
HuiXin.Gateway.Ocelot/Authorizers/HttpRolesAuthorizer.cs

@ -0,0 +1,49 @@
using Flurl;
using Flurl.Http;
using HuiXin.Gateway.Ocelot.Configurations;
using Microsoft.Extensions.Options;
using Ocelot.Errors;
using Ocelot.Infrastructure.Claims.Parser;
using Ocelot.Responses;
using Serilog;
namespace HuiXin.Gateway.Ocelot.Authorizers
{
public class HttpRolesAuthorizer : RolesAuthorizerBase, IRolesAuthorizer
{
private readonly string _url;
private readonly FlurlClient _client;
public HttpRolesAuthorizer(IClaimsParser claimsParser, IOptions<RolesAuthorizerConfiguration> configuration) : base(claimsParser, configuration)
{
_url = _configs.Url ?? throw new Exception("未配置角色验证的Url地址");
_client = new FlurlClient(_url);
_client.Settings.Timeout = TimeSpan.FromMilliseconds(_configs.Timeout);
_client.Settings.Redirects.Enabled = false;
}
public async Task<Response<bool>> Authorize(List<string> roles, string path)
{
try
{
bool pass = await _client.Request().AppendQueryParam("roles", roles).AppendQueryParam("path", path).GetJsonAsync<bool>();
if (pass)
{
return await ReturnAsync(new OkResponse<bool>(true));
}
else
{
return await ReturnAsync(new ErrorResponse<bool>(new HttpRolesAuthorizerFail("用户没有访问权限")));
}
}
catch (Exception ex)
{
Log.Error(ex.Message, "验证用户角色权限出错");
return await ReturnAsync(new ErrorResponse<bool>(new HttpRolesAuthorizerError("验证用户角色权限出错")));
}
}
}
public class HttpRolesAuthorizerError(string message) : Error(message, OcelotErrorCode.UnableToCompleteRequestError, 500){}
public class HttpRolesAuthorizerFail(string message) : Error(message, OcelotErrorCode.UnauthorizedError, 403){}
}

9
HuiXin.Gateway.Ocelot/Authorizers/IRolesAuthorizer.cs

@ -0,0 +1,9 @@
using Ocelot.Responses;
namespace HuiXin.Gateway.Ocelot.Authorizers
{
public interface IRolesAuthorizer
{
Task<Response<bool>> Authorize(List<string> roles, string path);
}
}

24
HuiXin.Gateway.Ocelot/Authorizers/RolesAuthorizerBase.cs

@ -0,0 +1,24 @@
using HuiXin.Gateway.Ocelot.Configurations;
using Microsoft.Extensions.Options;
using Ocelot.Infrastructure.Claims.Parser;
using Ocelot.Responses;
namespace HuiXin.Gateway.Ocelot.Authorizers
{
public class RolesAuthorizerBase
{
protected readonly IClaimsParser _claimsParser;
protected RolesAuthorizerConfiguration _configs;
public RolesAuthorizerBase(IClaimsParser claimsParser, IOptions<RolesAuthorizerConfiguration> cfg)
{
_claimsParser = claimsParser;
_configs = cfg.Value ?? throw new Exception("未配置角色验证参数");
}
protected async Task<Response<T>> ReturnAsync<T>(Response<T> response)
{
return await Task.FromResult(response);
}
}
}

6
HuiXin.Gateway.Ocelot/Configs/jwt.json

@ -0,0 +1,6 @@
{
"AuthenticationScheme": "MyKey",
"Authority": "http://localhost:5001",
"Audience": "huixin",
"IssuerSigningKeyBase64": "GcTdqSZdpRxBtdtgwvDHBzS427VGTQzbM+JD1CBbUZY="
}

54
HuiXin.Gateway.Ocelot/Configs/ocelot.json

@ -0,0 +1,54 @@
{
"Routes": [
{
"UpstreamHttpMethod": [ "Get" ],
"UpstreamPathTemplate": "/user/{postId}",
"DownstreamPathTemplate": "/search?q=/{postId}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 443
}
],
"QoSOptions": {
"TimeoutValue": 5000
},
//"ServiceName": "auth",
"LoadBalancerOptions": {
"Type": "LeastConnection"
},
"AuthenticationOptions": {
"AuthenticationProviderKey": "MyKey",
"AllowedScopes": [ "all" ]
}
},
{
"UpstreamHttpMethod": [ "Get" ],
"UpstreamPathTemplate": "/{url}",
"DownstreamPathTemplate": "/search?q={url}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "cn.bing.com",
"Port": 443
}
]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://api.mybusiness.com",
"RequestIdKey": "TraceId"
//"ServiceDiscoveryProvider": {
// "Scheme": "https",
// "Host": "localhost",
// "Port": 8500,
// "Type": "Consul"
//}
},
"RolesAuthorizer": {
"Type": "http",
"Url": "http://auth.huixin.com/api/authorizer",
"Timeout": 2000
}
}

15
HuiXin.Gateway.Ocelot/Configs/serilog.json

@ -0,0 +1,15 @@
{
"Serilog": {
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "./Logs/gateway.txt",
"rollingInterval": "Day",
"fileSizeLimitBytes": 20971520
}
},
{ "Name": "Console" }
]
}
}

9
HuiXin.Gateway.Ocelot/Configurations/RolesAuthorizerConfiguration.cs

@ -0,0 +1,9 @@
namespace HuiXin.Gateway.Ocelot.Configurations
{
public class RolesAuthorizerConfiguration
{
public string Type { get; set; }
public string Url { get; set; }
public int Timeout { get; set; }
}
}

46
HuiXin.Gateway.Ocelot/Extensions/JWTExtensions.cs

@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
namespace HuiXin.Gateway.Ocelot.Extensions
{
public static class JWTExtensions
{
public static IServiceCollection AddJWT(this IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configuration.GetValue<string>("AuthenticationScheme") ?? throw new Exception("jwt的参数AuthenticationScheme未配置,请在jwt.json文件中配置"), options =>
{
//options.Authority = cfgJwt.GetValue<string>("Authority"); // OpenIddict服务端地址
//options.BackchannelTimeout = TimeSpan.FromMilliseconds(300);
options.RequireHttpsMetadata = false;
options.Audience = configuration.GetValue<string>("Audience"); // 与OpenIddict中定义的Audience匹配
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = false,
IssuerSigningKey = new SymmetricSecurityKey(Convert.FromBase64String(configuration.GetValue<string>("IssuerSigningKeyBase64") ?? throw new Exception("jwt的参数IssuerSigningKeyBase64未配置,请在jwt.json文件中配置"))),
ValidateIssuer = false,
//ValidIssuer = "YOUR_ISSUER",
ValidateAudience = false,
//ValidAudience = "YOUR_AUDIENCE",
ValidateLifetime = true,
// 忽略 kid 参数
ValidateTokenReplay = false,
};
});
services.AddAuthorization();
return services;
}
public static IApplicationBuilder UseJWT(this WebApplication app)
{
app.UseAuthentication();
app.UseAuthorization();
return app;
}
}
}

64
HuiXin.Gateway.Ocelot/Extensions/OcelotExtensions.cs

@ -0,0 +1,64 @@
using HuiXin.Gateway.Ocelot.Authorizers;
using HuiXin.Gateway.Ocelot.Configurations;
using HuiXin.Gateway.Ocelot.Middlewares;
using Ocelot.Authorization;
using Ocelot.DependencyInjection;
using Ocelot.Infrastructure.Claims.Parser;
using Ocelot.Middleware;
using Ocelot.Provider.Consul;
using System.Security.Claims;
namespace HuiXin.Gateway.Ocelot.Extensions
{
public static class OcelotExtensions
{
public static IServiceCollection AddMyOcelot(this IServiceCollection services, IConfiguration configuration)
{
services.AddOcelot().AddConsul();
services.AddSingleton<IRolesAuthorizer, HttpRolesAuthorizer>();
services.Configure<RolesAuthorizerConfiguration>(configuration.GetSection("RolesAuthorizer"));
return services;
}
public static IApplicationBuilder UseMyOcelot(this WebApplication app)
{
app.UseMiddleware<AccessLoggingMiddleware>();
app.UseOcelot(new OcelotPipelineConfiguration
{
PreQueryStringBuilderMiddleware = async (context, next) =>
{
var claimsParser = app.Services.GetRequiredService<IClaimsParser>();
var values = claimsParser.GetValuesByClaimType(context.User.Claims, ClaimsIdentity.DefaultRoleClaimType);
if (values.IsError)
{
context.Items.UpsertErrors(values.Errors);
return;
}
if (values.Data == null || values.Data.Count == 0)
{
context.Items.SetError(new UserDoesNotHaveClaimError("token中未包含角色信息"));
return;
}
var downstreamRoute = context.Items.DownstreamRoute();
var url = downstreamRoute.DownstreamPathTemplate.Value;
context.Items.TemplatePlaceholderNameAndValues().ForEach(nv =>
{
url = url.Replace(nv.Name, nv.Value);
});
var rolesAuthorizer = app.Services.GetRequiredService<IRolesAuthorizer>();
var result = await rolesAuthorizer.Authorize(values.Data, url);
if (result.IsError)
{
context.Items.UpsertErrors(result.Errors);
return;
}
await next.Invoke();
}
}).Wait();
return app;
}
}
}

23
HuiXin.Gateway.Ocelot/HuiXin.Gateway.Ocelot.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Flurl.Http" Version="4.0.2" />
<PackageReference Include="JWT" Version="10.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.3" />
<PackageReference Include="Ocelot" Version="23.1.0" />
<PackageReference Include="Ocelot.Provider.Consul" Version="23.1.0" />
<PackageReference Include="Ocelot.Provider.Polly" Version="23.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>
</Project>

64
HuiXin.Gateway.Ocelot/JWTUtil.cs

@ -0,0 +1,64 @@
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace HuiXin.Gateway.Ocelot
{
public class JWTUtil
{
/// <summary>
/// 创建token
/// </summary>
/// <returns></returns>
public static string CreateJwtToken(IDictionary<string, object> payload, string secret, IDictionary<string, string> extraHeaders = null)
{
//IJwtEncoder encoder = new JwtEncoder(new HMACSHA256Algorithm(), new JsonNetSerializer(), new JwtBase64UrlEncoder());
//var token = encoder.Encode(extraHeaders,payload, secret);
//return token;
Claim[] claims = new Claim[]
{
new Claim("Id", "aaa"),
new Claim("Name", "bbb"),
new Claim("Email", "ccc"),
};
var securityKey = new SymmetricSecurityKey(Convert.FromBase64String("GcTdqSZdpRxBtdtgwvDHBzS427VGTQzbM+JD1CBbUZY="));
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var header = new JwtHeader(signingCredentials);
//header.Add("typ", "JWT"); // 默认情况下,typ通常是"JWT",但你可以明确设置它
//header.Add("kid", "MyKey");
//header.Add("key", "MyKey");
//header.Add("keyid", "MyKey");
// 设置JWT载荷(payload)
var payload1 = new JwtPayload
{
//{ "kid", "MyKey" },
//{ "key", "MyKey" },
//{ "keyid", "MyKey" },
{ "issuer",""},
{ "sub", "1234567890" },
{ "name", "测试用户" },
{ "role", new []{"test","admin" } },
{ "scope",new []{"all" } },
{ "iat", ToUnixTime(DateTime.Now)},
{ "exp", ToUnixTime(DateTime.Now.AddDays(1)) }
};
// 创建JwtSecurityToken实例并结合header和payload
var jwt = new JwtSecurityToken(header, payload1);
return new JwtSecurityTokenHandler().WriteToken(jwt);
}
private static long ToUnixTime(DateTime dt)
{
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (long)(dt.ToUniversalTime() - epoch).TotalMilliseconds;
}
}
}

132
HuiXin.Gateway.Ocelot/Middlewares/AccessLoggingMiddleware.cs

@ -0,0 +1,132 @@
using Microsoft.AspNetCore.Http.Extensions;
using Ocelot.RequestId;
using Serilog;
using System.Diagnostics;
using System.Text;
using Yitter.IdGenerator;
namespace HuiXin.Gateway.Ocelot.Middlewares
{
public class AccessLoggingMiddleware
{
private readonly RequestDelegate _next;
public AccessLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var traceIdKey = DefaultRequestIdKey.Value;
var traceId = YitIdHelper.NextId().ToString();
context.TraceIdentifier = traceId;
context.Request.Headers[traceIdKey] = traceId;
var sw = Stopwatch.StartNew();
sw.Start();
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("-------------------Request Start-------------------");
sb.AppendLine(DateTime.Now.ToString());
sb.AppendLine($"追踪id:{traceId}");
sb.AppendLine($"地址:{context.Request.GetDisplayUrl()}");
sb.AppendLine("请求头:");
foreach (var header in context.Request.Headers)
{
sb.AppendLine($"{header.Key}:{header.Value}");
}
sb.AppendLine($"数据:{await GetRequestBody(context.Request)}");
sb.AppendLine("===================Request End===================");
Log.Information(sb.ToString());
sb.Clear();
//Copy a pointer to the original response body stream
var originalBodyStream = context.Response.Body;
//Create a new memory stream...
using var responseBody = new MemoryStream();
//...and use that for the temporary response body
context.Response.Body = responseBody;
//Continue down the Middleware pipeline, eventually returning to this class
await _next(context);
//Format the response from the server
//var response = await FormatResponse(context.Response);
sb.AppendLine();
sb.AppendLine("-------------------Response Start-------------------");
sb.AppendLine(DateTime.Now.ToString());
sb.AppendLine($"追踪id:{traceId}");
sb.AppendLine($"耗时:{sw.ElapsedMilliseconds}毫秒");
sb.AppendLine($"状态码:{context.Response.StatusCode}");
//sb.AppendLine("Headers: ");
//foreach (var header in context.Response.Headers)
//{
// sb.AppendLine($"{header.Key}:{header.Value}");
//}
sb.AppendLine($"数据:{await GetResponseBody(context.Response)}");
sb.AppendLine("===================Response End===================");
//Save log to chosen datastore
Log.Information(sb.ToString());
sb.Clear();
//Copy the contents of the new memory stream (which contains the response) to the original stream, which is then returned to the client.
await responseBody.CopyToAsync(originalBodyStream);
}
private static async Task<string> GetRequestBody(HttpRequest request)
{
request.EnableBuffering();
// Leave the body open so the next middleware can read it.
using var reader = new StreamReader(
request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
leaveOpen: true);
var body = await reader.ReadToEndAsync();
// Do some processing with body…
//var formattedRequest = $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {body}";
// Reset the request body stream position so the next middleware can read it
request.Body.Position = 0;
return body;
}
private static async Task<string> GetResponseBody(HttpResponse response)
{
//We need to read the response stream from the beginning...
response.Body.Seek(0, SeekOrigin.Begin);
//...and copy it into a string
string text = await new StreamReader(response.Body).ReadToEndAsync();
//We need to reset the reader for the response so that the client can read it.
response.Body.Seek(0, SeekOrigin.Begin);
//Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
//return $"{response.StatusCode}: {text}";
return text;
}
static AccessLoggingMiddleware()
{
// 创建 IdGeneratorOptions 对象,可在构造函数中输入 WorkerId:
var options = new IdGeneratorOptions();
// options.WorkerIdBitLength = 10; // 默认值6,限定 WorkerId 最大值为2^6-1,即默认最多支持64个节点。
// options.SeqBitLength = 6; // 默认值6,限制每毫秒生成的ID个数。若生成速度超过5万个/秒,建议加大 SeqBitLength 到 10。
// options.BaseTime = Your_Base_Time; // 如果要兼容老系统的雪花算法,此处应设置为老系统的BaseTime。
// ...... 其它参数参考 IdGeneratorOptions 定义。
// 保存参数(务必调用,否则参数设置不生效):
YitIdHelper.SetIdGenerator(options);
}
}
}

34
HuiXin.Gateway.Ocelot/Middlewares/MyAuthorizationMiddleware.cs

@ -0,0 +1,34 @@
using Ocelot.Infrastructure.Claims.Parser;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.Responses;
namespace HuiXin.Gateway.Ocelot.Middlewares
{
public class MyAuthorizationMiddleware : OcelotMiddleware
{
private readonly RequestDelegate _next;
private readonly IClaimsParser _claimsParser;
public MyAuthorizationMiddleware(RequestDelegate next,
IClaimsParser claimsParser,
IOcelotLoggerFactory loggerFactory)
: base(loggerFactory.CreateLogger<MyAuthorizationMiddleware>())
{
_next = next;
_claimsParser = claimsParser;
}
public async Task Invoke(HttpContext httpContext)
{
Authorize(httpContext);
await _next.Invoke(httpContext);
}
public Response<bool> Authorize(HttpContext httpContext)
{
var values = _claimsParser.GetValuesByClaimType(httpContext.User.Claims, "role");
return new OkResponse<bool>(true);
}
}
}

78
HuiXin.Gateway.Ocelot/Program.cs

@ -0,0 +1,78 @@
using HuiXin.Gateway.Ocelot.Extensions;
using Serilog;
using System.Security.Cryptography;
namespace HuiXin.Gateway.Ocelot
{
public class Program
{
public static void Main(string[] args)
{
//BuildJwt();
var configuration = new ConfigurationBuilder()
.AddJsonFile("Configs/ocelot.json", false, true)
.AddJsonFile("Configs/jwt.json", false, false)
.AddJsonFile("Configs/serilog.json", false, true)
.Build();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Log.Logger = logger;
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddConfiguration(configuration);
var services = builder.Services;
services.AddCors();
services.AddLogging(loggingBuilder => loggingBuilder.ClearProviders().AddSerilog());
services.AddJWT(configuration);
services.AddMyOcelot(configuration);
var app = builder.Build();
app.UseCors();
app.UseJWT();
app.UseMyOcelot();
app.Run();
Log.Information("系统已启动");
}
catch (Exception ex)
{
Log.Fatal(ex, "系统异常");
}
finally
{
Log.CloseAndFlush();
}
}
static void BuildJwt()
{
using var aes = Aes.Create();
aes.KeySize = 256;
aes.GenerateKey();
var sign = Convert.ToBase64String(aes.Key);
var extraHeaders = new Dictionary<string, string> { { "kid", "MyKey" } };
//过期时间(可以不设置,下面表示签名后 10秒过期)
double exp = (DateTime.UtcNow.AddDays(10) - new DateTime(1970, 1, 1)).TotalSeconds;
var payload = new Dictionary<string, object>
{
{ "userId", "001" },
{ "userAccount", "fan" },
{ "exp",exp }
};
Console.WriteLine("Token:" + JWTUtil.CreateJwtToken(payload, sign, extraHeaders));
}
}
}

30
HuiXin.Gateway.Ocelot/Properties/launchSettings.json

@ -0,0 +1,30 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:21406",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5000",
"launchUrl": "user/getById",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

9
HuiXin.Gateway.Ocelot/appsettings.Development.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Ocelot": "Error"
}
}
}

9
HuiXin.Gateway.Ocelot/appsettings.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

13
HuiXin.Gateway.Yarp/HuiXin.Gateway.Yarp.csproj

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Yarp.ReverseProxy" Version="2.1.0" />
</ItemGroup>
</Project>

15
HuiXin.Gateway.Yarp/Program.cs

@ -0,0 +1,15 @@
namespace HuiXin.Gateway.Yarp
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
}
}
}

29
HuiXin.Gateway.Yarp/Properties/launchSettings.json

@ -0,0 +1,29 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:17782",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5167",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

8
HuiXin.Gateway.Yarp/appsettings.Development.json

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
HuiXin.Gateway.Yarp/appsettings.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

37
HuiXin.Gateway.sln

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuiXin.Gateway.Ocelot", "HuiXin.Gateway.Ocelot\HuiXin.Gateway.Ocelot.csproj", "{2E2162C5-FC45-478B-83D4-14148477D627}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuiXin.Identity.OpenIddict", "HuiXin.Identity.OpenIddict\HuiXin.Identity.OpenIddict.csproj", "{819D01DC-9EFE-427E-B73E-9022DC7843EC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuiXin.Gateway.Yarp", "HuiXin.Gateway.Yarp\HuiXin.Gateway.Yarp.csproj", "{55A12844-A4CE-407A-BD7C-94469AA407F0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2E2162C5-FC45-478B-83D4-14148477D627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E2162C5-FC45-478B-83D4-14148477D627}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E2162C5-FC45-478B-83D4-14148477D627}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E2162C5-FC45-478B-83D4-14148477D627}.Release|Any CPU.Build.0 = Release|Any CPU
{819D01DC-9EFE-427E-B73E-9022DC7843EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{819D01DC-9EFE-427E-B73E-9022DC7843EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{819D01DC-9EFE-427E-B73E-9022DC7843EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{819D01DC-9EFE-427E-B73E-9022DC7843EC}.Release|Any CPU.Build.0 = Release|Any CPU
{55A12844-A4CE-407A-BD7C-94469AA407F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55A12844-A4CE-407A-BD7C-94469AA407F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55A12844-A4CE-407A-BD7C-94469AA407F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55A12844-A4CE-407A-BD7C-94469AA407F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8F9B214D-FFA3-4E2C-8103-6A92331507EA}
EndGlobalSection
EndGlobal

12
HuiXin.Identity.OpenIddict/ApplicationDbContext.cs

@ -0,0 +1,12 @@
using Microsoft.EntityFrameworkCore;
namespace HuiXin.Identity.OpenIddict
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options)
: base(options)
{
}
}
}

357
HuiXin.Identity.OpenIddict/Controllers/AuthorizationController.cs

@ -0,0 +1,357 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using OpenIddict.Abstractions;
using OpenIddict.Server.AspNetCore;
using System.Collections.Immutable;
using System.Security.Claims;
using static OpenIddict.Abstractions.OpenIddictConstants;
namespace HuiXin.Identity.OpenIddict.Controllers
{
[ApiController]
[Route("auth")]
public class AuthorizationController : Controller
{
private readonly IOpenIddictApplicationManager _applicationManager;
private readonly IOpenIddictAuthorizationManager _authorizationManager;
private readonly IOpenIddictScopeManager _scopeManager;
public AuthorizationController(IOpenIddictApplicationManager applicationManager, IOpenIddictAuthorizationManager authorizationManager, IOpenIddictScopeManager scopeManager)
{
_applicationManager = applicationManager;
_scopeManager = scopeManager;
_authorizationManager = authorizationManager;
}
/// <summary>
/// 登录权限校验
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="Exception"></exception>
[HttpGet("connect/authorize")]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> Authorize()
{
// var s=await _schemeProvider.GetAllSchemesAsync();
//通过扩展的获取自定义的参数校验
var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("未获取到相关认证情况");
#region 存在登录凭证且明确了登录请求的行为
// 存在登录凭证且明确了登录请求的行为
if (request.HasPrompt(Prompts.Login))
{
//这里有个小坑,在Challenge之前必须把这个行为去掉 不然 Challenge 进入 /connect/authorize 路由陷入死循环
var prompt = string.Join(" ", request.GetPrompts().Remove(Prompts.Login));
var parameters = Request.HasFormContentType ?
Request.Form.Where(parameter => parameter.Key != Parameters.Prompt).ToList() :
Request.Query.Where(parameter => parameter.Key != Parameters.Prompt).ToList();
parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt)));
return Challenge(
authenticationSchemes: new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme }, // IdentityConstants.ApplicationScheme,
properties: new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
});
}
#endregion
//检索本地的Cookies信息 确定重定向页面 这里都是UTC时间来设置的过期情况 这里没有用Identity 所以这里可以指定自己的应用名称
var result = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); //IdentityConstants.ApplicationScheme
#region 未获取本地Cookies信息或者 cookie过期的情况
if (request == null || !result.Succeeded || (request.MaxAge != null && result.Properties?.IssuedUtc != null &&
DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value)))
{
//是否是无效授权
if (request.HasPrompt(Prompts.None))
{
return Forbid(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties(new Dictionary<string, string?>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "用户未登录."
}));
}
return Challenge(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(
Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList())
});
}
#endregion
//var resultdata = _userService.GetLoginInfo(new Guid(result.Principal.GetClaim(Claims.Subject) ?? throw new Exception("用户标识存在"))) ?? throw new Exception("用户详细信息不存在");
var resultdata = new UserInfo()
{
Id = "user1",
UserName = "测试用户名",
NickName = "测试昵称",
};
// 获取客户端详细信息 验证其他数据
var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ?? throw new InvalidOperationException("未查找到该客户端的应用详细信息");
//查找当前情况客户端下请求用户的持久化授权数据信息
var authorizations = _authorizationManager.FindAsync(
subject: resultdata.Id.ToString(),
client: await _applicationManager.GetIdAsync(application) ?? throw new Exception("没有找到客户端的应用信息"), //这里区分下 是application的Id而不是ClientId
status: Statuses.Valid,
type: AuthorizationTypes.Permanent,
scopes: request.GetScopes()
).ToBlockingEnumerable();//.ToListAsync();
var consenttype = await _applicationManager.GetConsentTypeAsync(application);
//获取授权同意确认页面
switch (consenttype)
{
//判断授权同意的类型
//1 外部允许的且没有任何授权项
case ConsentTypes.External when !authorizations.Any():
return Forbid(
authenticationSchemes: new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties(new Dictionary<string, string?>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
"登录用户没用访问该客户端应用的权限"
}));
// 隐式、外部授权、显示模式模式
case ConsentTypes.Implicit:
case ConsentTypes.External when authorizations.Any():
case ConsentTypes.Explicit when authorizations.Any() && !request.HasPrompt(Prompts.Consent):
ClaimsPrincipal principal = CreateUserPrincpal(resultdata);
//设置请求的范围
principal.SetScopes(request.GetScopes());
//查找scope允许访问的资源
var resources = _scopeManager.ListResourcesAsync(principal.GetScopes()).ToBlockingEnumerable();
//通过扩展设置不同的资源访问 其实本质都是设置Claims 只是 key 在 scope以及Resource上不同
//Resource = "oi_rsrc";
// Scope = "oi_scp";
principal.SetResources(resources);
// 自动创建一个永久授权,以避免需要明确的同意 用于包含相同范围的未来授权或令牌请求
var authorization = authorizations.LastOrDefault();
if (authorization is null)
{
authorization = await _authorizationManager.CreateAsync(
principal: principal,
subject: resultdata.Id.ToString(),
client: await _applicationManager.GetIdAsync(application),
type: AuthorizationTypes.Permanent,
scopes: principal.GetScopes());
}
principal.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
foreach (var claim in principal.Claims)
{
claim.SetDestinations(GetDestinations(claim, principal));
}
//登录 OpenIddict签发令牌
return SignIn(principal, null, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
// At this point, no authorization was found in the database and an error must be returned
// if the client application specified prompt=none in the authorization request.
case ConsentTypes.Explicit when request.HasPrompt(Prompts.None):
case ConsentTypes.Systematic when request.HasPrompt(Prompts.None):
return Forbid(
authenticationSchemes: new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties(new Dictionary<string, string?>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
"Interactive user consent is required."
}));
// In every other case, render the consent form.
//default:
// return View(new AuthorizeViewModel
// {
// ApplicationName = await _applicationManager.GetLocalizedDisplayNameAsync(application),
// Scope = request.Scope
// });
default:
return Challenge(
authenticationSchemes: new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties { RedirectUri = "/" }
);
}
}
[HttpPost("connect/token"), Produces("application/json")]
public async Task<IActionResult> ConnectToken()
{
var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("OIDC请求不存在");
if (request.IsClientCredentialsGrantType())
{
// Note: the client credentials are automatically validated by OpenIddict:
// if client_id or client_secret are invalid, this action won't be invoked.
var application = await _applicationManager.FindByClientIdAsync(request.ClientId);
if (application is null)
{
Console.WriteLine($"client_id未注册:{request.ClientId}");
throw new InvalidOperationException("The application cannot be found.");
}
Console.WriteLine($"获取到客户信息:{JsonConvert.SerializeObject(application)}");
// Create a new ClaimsIdentity containing the claims that
// will be used to create an id_token, a token or a code.
var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, Claims.Name, Claims.Role);
// Use the client_id as the subject identifier.
identity.SetClaim(Claims.Subject, await _applicationManager.GetClientIdAsync(application));
identity.SetClaim(Claims.Name, await _applicationManager.GetDisplayNameAsync(application));
identity.SetDestinations(static claim => claim.Type switch
{
// Allow the "name" claim to be stored in both the access and identity tokens
// when the "profile" scope was granted (by calling principal.SetScopes(...)).
Claims.Name when claim.Subject.HasScope(Scopes.Profile)
=> new[] { Destinations.AccessToken, Destinations.IdentityToken },
// Otherwise, only store the claim in the access tokens.
_ => new[] { Destinations.AccessToken }
});
//Console.WriteLine($"identity信息:{JsonConvert.SerializeObject(identity)}");
var result = SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
//Console.WriteLine($"signIn信息:{JsonConvert.SerializeObject(result)}");
return result;
}
else if (request.IsPasswordGrantType())
{
//数据库获取用户信息
var princpal = CreateUserPrincpal(new UserInfo()
{
Id = Guid.NewGuid().ToString(),
UserName = "测试用户名",
NickName = "测试昵称",
});
//princpal.SetResources(_scopeManager.ListResourcesAsync(princpal.GetScopes()));
foreach (var claim in princpal.Claims)
{
claim.SetDestinations(GetDestinations(claim, princpal));
}
return SignIn(princpal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
else if (request.IsAuthorizationCodeGrantType() || request.IsDeviceCodeGrantType() || request.IsRefreshTokenGrantType())
{
var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
//var user = _userService.GetLoginInfo(new Guid(principal?.GetClaim(Claims.Subject) ?? throw new Exception("用户标识存在")));
//UserInfo user = null;
//if (user == null)
//{
// return Forbid(
// authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
// properties: new AuthenticationProperties(new Dictionary<string, string?>
// {
// [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
// [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "令牌已失效"
// })
// );
//}
foreach (var claim in principal.Claims)
{
claim.SetDestinations(GetDestinations(claim, principal));
}
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
throw new InvalidOperationException($"不支持的grant_type:{request.GrantType}");
}
[HttpPost("connect/logout")]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync();
return SignOut(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties
{
RedirectUri = "/"
});
}
public static ClaimsPrincipal CreateUserPrincpal(UserInfo user, string claimsIdentityName = "USERINFO")
{
//登录成功流程
ClaimsIdentity identity = new ClaimsIdentity(claimsIdentityName);
identity.AddClaim(new Claim(Claims.Subject, user.Id));
identity.AddClaim(new Claim(Claims.Name, user.UserName));
identity.AddClaim(new Claim(Claims.Nickname, user.NickName));
return new ClaimsPrincipal(identity);
}
private IEnumerable<string> GetDestinations(Claim claim)
{
// Note: by default, claims are NOT automatically included in the access and identity tokens.
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
// whether they should be included in access tokens, in identity tokens or in both.
return claim.Type switch
{
Claims.Name or
Claims.Subject
=> ImmutableArray.Create(Destinations.AccessToken, Destinations.IdentityToken),
_ => ImmutableArray.Create(Destinations.AccessToken),
};
}
private IEnumerable<string> GetDestinations(Claim claim, ClaimsPrincipal principal)
{
switch (claim.Type)
{
case Claims.Name:
yield return Destinations.AccessToken;
if (principal.HasScope(Scopes.Profile))
yield return Destinations.IdentityToken;
yield break;
case Claims.Email:
yield return Destinations.AccessToken;
if (principal.HasScope(Scopes.Email))
yield return Destinations.IdentityToken;
yield break;
case Claims.Role:
yield return Destinations.AccessToken;
if (principal.HasScope(Scopes.Roles))
yield return Destinations.IdentityToken;
yield break;
case "AspNet.Identity.SecurityStamp": yield break;
default:
yield return Destinations.AccessToken;
yield break;
}
}
}
}

21
HuiXin.Identity.OpenIddict/Controllers/UserController.cs

@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Mvc;
using OpenIddict.Abstractions;
namespace HuiXin.Identity.OpenIddict.Controllers
{
[ApiController]
[Route("user")]
public class UserController : Controller
{
private readonly IOpenIddictApplicationManager _applicationManager;
private readonly IOpenIddictAuthorizationManager _authorizationManager;
private readonly IOpenIddictScopeManager _scopeManager;
public UserController(IOpenIddictApplicationManager applicationManager, IOpenIddictAuthorizationManager authorizationManager, IOpenIddictScopeManager scopeManager)
{
_applicationManager = applicationManager;
_scopeManager = scopeManager;
_authorizationManager = authorizationManager;
}
}
}

19
HuiXin.Identity.OpenIddict/HuiXin.Identity.OpenIddict.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OpenIddict.AspNetCore" Version="5.3.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="5.3.0" />
<PackageReference Include="OpenIddict.Validation.AspNetCore" Version="5.3.0" />
</ItemGroup>
</Project>

108
HuiXin.Identity.OpenIddict/Program.cs

@ -0,0 +1,108 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Validation.AspNetCore;
using System.Text;
namespace HuiXin.Identity.OpenIddict
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddCors();
builder.Services.AddControllers();
builder.Services
.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)
.AddCookie();
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
//options.UseSqlite("DataSource=:memory:");
options.UseMySQL("server=8.134.236.110;port=13306;database=openiddict;user=test;password=test")
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
// Register the entity sets needed by OpenIddict.
// Note: use the generic overload if you need to replace the default OpenIddict entities.
options.UseOpenIddict();
});
builder.Services.AddIdentity<UserInfo, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
builder.Services
.AddOpenIddict()
// Register the OpenIddict core components.
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
// Note: call ReplaceDefaultEntities() to replace the default entities.
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
// Register the OpenIddict server components.
.AddServer(options =>
{
options.SetAccessTokenLifetime(TimeSpan.FromMinutes(5));
options.SetIdentityTokenLifetime(TimeSpan.FromMinutes(5));
options.SetRefreshTokenLifetime(TimeSpan.FromDays(365 * 100));
// Enable the token endpoint.
options.SetTokenEndpointUris("auth/connect/token");
options.SetAuthorizationEndpointUris("auth/connect/authorize");
options.SetUserinfoEndpointUris("auth/connect/userinfo");
options.SetLogoutEndpointUris("auth/connect/logout");
// Enable the client credentials flow.
options.AllowClientCredentialsFlow();
options.AllowAuthorizationCodeFlow();
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
// Register the signing and encryption credentials.
options.AddEncryptionKey(new SymmetricSecurityKey(Convert.FromBase64String("GcTdqSZdpRxBtdtgwvDHBzS427VGTQzbM+JD1CBbUZY=")));
options.AddDevelopmentSigningCertificate();
// Register the ASP.NET Core host and configure the ASP.NET Core options.
options.UseAspNetCore()
.EnableTokenEndpointPassthrough()
.EnableAuthorizationEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.DisableTransportSecurityRequirement();
options.IgnoreEndpointPermissions();
options.IgnoreGrantTypePermissions();
options.IgnoreScopePermissions();
options.IgnoreResponseTypePermissions();
})
// Register the OpenIddict validation components.
.AddValidation(options =>
{
// Import the configuration from the local OpenIddict server instance.
options.UseLocalServer();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
builder.Services.AddHostedService<Worker>();
var app = builder.Build();
// Configure the HTTP request pipeline.
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}

29
HuiXin.Identity.OpenIddict/Properties/launchSettings.json

@ -0,0 +1,29 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:61533",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

11
HuiXin.Identity.OpenIddict/UserInfo.cs

@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Identity;
namespace HuiXin.Identity.OpenIddict
{
public class UserInfo : IdentityUser
{
public string Id { get; set; }
public string UserName { get; set; }
public string NickName { get; set; }
}
}

41
HuiXin.Identity.OpenIddict/Worker.cs

@ -0,0 +1,41 @@
using OpenIddict.Abstractions;
namespace HuiXin.Identity.OpenIddict
{
public class Worker : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public Worker(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await context.Database.EnsureCreatedAsync(cancellationToken);
var manager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
//var authManager = scope.ServiceProvider.GetRequiredService<IOpenIddictAuthorizationManager>();
var data = await manager.FindByClientIdAsync("apisix", cancellationToken) ?? await manager.CreateAsync(
new OpenIddictApplicationDescriptor
{
ClientId = "apisix",
ClientSecret = "388D45FA-B36B-4988-BA59-B187D329C207",
DisplayName = "APISIX的测试客户",
Permissions =
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.Token
},
RedirectUris = { new Uri("http://8.134.191.93:9080/test/callback")},
}, cancellationToken);
//await manager.DeleteAsync(data);
Console.WriteLine($"APISIX的测试客户:{System.Text.Json.JsonSerializer.Serialize(data)}");
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}

8
HuiXin.Identity.OpenIddict/appsettings.Development.json

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
HuiXin.Identity.OpenIddict/appsettings.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Loading…
Cancel
Save