Compare commits
10 Commits
7c92208c40
...
9f02398eb9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f02398eb9 | ||
|
|
a8656ca982 | ||
|
|
7a9fcf9fc1 | ||
|
|
d4aff05804 | ||
|
|
39cc9a8538 | ||
| 8184f77c0f | |||
|
|
5d097d8582 | ||
|
|
0c5bd5e647 | ||
|
|
1a0c18c198 | ||
|
|
875ba7bc61 |
31
Configuration/FormValueRequiredAttribute.cs
Normal file
31
Configuration/FormValueRequiredAttribute.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||||
|
|
||||||
|
namespace Fengling.AuthService.Configuration;
|
||||||
|
|
||||||
|
public sealed class FormValueRequiredAttribute(string name) : ActionMethodSelectorAttribute
|
||||||
|
{
|
||||||
|
public override bool IsValidForRequest(RouteContext context, ActionDescriptor action)
|
||||||
|
{
|
||||||
|
if (string.Equals(context.HttpContext.Request.Method, "GET", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(context.HttpContext.Request.Method, "HEAD", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(context.HttpContext.Request.Method, "DELETE", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(context.HttpContext.Request.Method, "TRACE", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(context.HttpContext.Request.ContentType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context.HttpContext.Request.ContentType.StartsWith("application/x-www-form-urlencoded",
|
||||||
|
StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !string.IsNullOrEmpty(context.HttpContext.Request.Form[name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using OpenIddict.Abstractions;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Configuration;
|
namespace Fengling.AuthService.Configuration;
|
||||||
|
|
||||||
@ -11,48 +14,83 @@ public static class OpenIddictSetup
|
|||||||
IConfiguration configuration
|
IConfiguration configuration
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
services.Configure<IdentityOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ClaimsIdentity.UserNameClaimType = OpenIddictConstants.Claims.Name;
|
||||||
|
options.ClaimsIdentity.UserIdClaimType = OpenIddictConstants.Claims.Subject;
|
||||||
|
options.ClaimsIdentity.RoleClaimType = OpenIddictConstants.Claims.Role;
|
||||||
|
options.ClaimsIdentity.EmailClaimType = OpenIddictConstants.Claims.Email;
|
||||||
|
options.SignIn.RequireConfirmedAccount = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddQuartz(options =>
|
||||||
|
{
|
||||||
|
options.UseSimpleTypeLoader();
|
||||||
|
options.UseInMemoryStore();
|
||||||
|
});
|
||||||
var isTesting = configuration.GetValue<bool>("Testing", false);
|
var isTesting = configuration.GetValue<bool>("Testing", false);
|
||||||
|
|
||||||
var builder = services.AddOpenIddict();
|
var builder = services.AddOpenIddict();
|
||||||
|
|
||||||
builder.AddCore(options =>
|
builder.AddCore(options =>
|
||||||
{
|
{
|
||||||
options.UseEntityFrameworkCore().UseDbContext<Data.ApplicationDbContext>();
|
options.UseEntityFrameworkCore()
|
||||||
|
.UseDbContext<Platform.Infrastructure.PlatformDbContext>();
|
||||||
|
options.UseQuartz();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isTesting)
|
if (!isTesting)
|
||||||
{
|
{
|
||||||
builder.AddServer(options =>
|
builder.AddServer(options =>
|
||||||
{
|
{
|
||||||
options.SetIssuer(configuration["OpenIddict:Issuer"] ?? "https://auth.fengling.local");
|
options.SetIssuer(configuration["OpenIddict:Issuer"] ?? "http://localhost:5132");
|
||||||
|
|
||||||
|
options.SetAuthorizationEndpointUris("connect/authorize")
|
||||||
|
.SetIntrospectionEndpointUris("connect/introspect")
|
||||||
|
.SetEndSessionEndpointUris("connect/endsession")
|
||||||
|
.SetTokenEndpointUris("connect/token")
|
||||||
|
.SetUserInfoEndpointUris("connect/userinfo")
|
||||||
|
.SetEndUserVerificationEndpointUris("connect/verify");
|
||||||
|
|
||||||
|
options.AllowAuthorizationCodeFlow()
|
||||||
|
.AllowHybridFlow()
|
||||||
|
.AllowClientCredentialsFlow()
|
||||||
|
.AllowRefreshTokenFlow();
|
||||||
|
|
||||||
options.AddDevelopmentEncryptionCertificate()
|
options.AddDevelopmentEncryptionCertificate()
|
||||||
.AddDevelopmentSigningCertificate();
|
.AddDevelopmentSigningCertificate();
|
||||||
|
|
||||||
options.AllowAuthorizationCodeFlow()
|
options.DisableAccessTokenEncryption();
|
||||||
.AllowPasswordFlow()
|
|
||||||
.AllowRefreshTokenFlow()
|
|
||||||
.RequireProofKeyForCodeExchange();
|
|
||||||
|
|
||||||
options.RegisterScopes(
|
options.RegisterScopes(OpenIddictConstants.Scopes.OfflineAccess, OpenIddictConstants.Scopes.Email,
|
||||||
"openid",
|
OpenIddictConstants.Scopes.Profile, OpenIddictConstants.Scopes.OpenId,
|
||||||
"profile",
|
OpenIddictConstants.Permissions.Scopes.Roles,
|
||||||
"email",
|
|
||||||
"api",
|
"api",
|
||||||
"offline_access"
|
"auth_server_admin");
|
||||||
);
|
|
||||||
|
options
|
||||||
|
.UseReferenceAccessTokens()
|
||||||
|
.UseReferenceRefreshTokens()
|
||||||
|
.UseAspNetCore()
|
||||||
|
.DisableTransportSecurityRequirement()
|
||||||
|
.EnableAuthorizationEndpointPassthrough()
|
||||||
|
.EnableEndSessionEndpointPassthrough()
|
||||||
|
.EnableTokenEndpointPassthrough()
|
||||||
|
.EnableUserInfoEndpointPassthrough()
|
||||||
|
.EnableStatusCodePagesIntegration();
|
||||||
|
|
||||||
|
options.SetAccessTokenLifetime(TimeSpan.FromHours(24));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddValidation(options =>
|
builder.AddValidation(options =>
|
||||||
{
|
{
|
||||||
options.UseLocalServer();
|
options.UseLocalServer();
|
||||||
|
options.UseAspNetCore();
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
{
|
|
||||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
|
||||||
});
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using Fengling.AuthService.Data;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -11,11 +12,11 @@ namespace Fengling.AuthService.Controllers;
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class AccessLogsController : ControllerBase
|
public class AccessLogsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly PlatformDbContext _context;
|
||||||
private readonly ILogger<AccessLogsController> _logger;
|
private readonly ILogger<AccessLogsController> _logger;
|
||||||
|
|
||||||
public AccessLogsController(
|
public AccessLogsController(
|
||||||
ApplicationDbContext context,
|
PlatformDbContext context,
|
||||||
ILogger<AccessLogsController> logger)
|
ILogger<AccessLogsController> logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Fengling.AuthService.ViewModels;
|
using Fengling.AuthService.ViewModels;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
@ -10,25 +14,14 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
|
|
||||||
[Route("account")]
|
[Route("account")]
|
||||||
public class AccountController : Controller
|
public class AccountController(
|
||||||
{
|
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
|
||||||
private readonly ApplicationDbContext _dbContext;
|
|
||||||
private readonly ILogger<AccountController> _logger;
|
|
||||||
|
|
||||||
public AccountController(
|
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
SignInManager<ApplicationUser> signInManager,
|
SignInManager<ApplicationUser> signInManager,
|
||||||
ApplicationDbContext dbContext,
|
PlatformDbContext dbContext,
|
||||||
ILogger<AccountController> logger)
|
ILogger<AccountController> logger,
|
||||||
{
|
PlatformDbContext platformDbContext)
|
||||||
_userManager = userManager;
|
: Controller
|
||||||
_signInManager = signInManager;
|
{
|
||||||
_dbContext = dbContext;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("login")]
|
[HttpGet("login")]
|
||||||
public IActionResult Login(string returnUrl = "/")
|
public IActionResult Login(string returnUrl = "/")
|
||||||
{
|
{
|
||||||
@ -44,14 +37,14 @@ public class AccountController : Controller
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = await _userManager.FindByNameAsync(model.Username);
|
var user = await userManager.FindByNameAsync(model.Username);
|
||||||
if (user == null || user.IsDeleted)
|
if (user == null || user.IsDeleted)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(string.Empty, "用户名或密码错误");
|
ModelState.AddModelError(string.Empty, "用户名或密码错误");
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await _signInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, false);
|
var result = await signInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, true);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
if (result.IsLockedOut)
|
if (result.IsLockedOut)
|
||||||
@ -83,12 +76,12 @@ public class AccountController : Controller
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultTenant = await _dbContext.Tenants
|
var tenant = await platformDbContext.Tenants
|
||||||
.FirstOrDefaultAsync(t => t.TenantId == "default");
|
.FirstOrDefaultAsync(t => t.TenantCode == model.TenantCode);
|
||||||
|
|
||||||
if (defaultTenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(string.Empty, "系统配置错误:未找到默认租户");
|
ModelState.AddModelError(string.Empty, $"系统配置错误:未找到租户{model.TenantCode}");
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,10 +91,10 @@ public class AccountController : Controller
|
|||||||
Email = model.Email,
|
Email = model.Email,
|
||||||
NormalizedUserName = model.Username.ToUpper(),
|
NormalizedUserName = model.Username.ToUpper(),
|
||||||
NormalizedEmail = model.Email.ToUpper(),
|
NormalizedEmail = model.Email.ToUpper(),
|
||||||
TenantInfo = new TenantInfo(defaultTenant.Id, defaultTenant.TenantId, defaultTenant.Name)
|
TenantInfo = new TenantInfo(tenant)
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = await _userManager.CreateAsync(user, model.Password);
|
var result = await userManager.CreateAsync(user, model.Password);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
foreach (var error in result.Errors)
|
foreach (var error in result.Errors)
|
||||||
@ -111,23 +104,23 @@ public class AccountController : Controller
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
await signInManager.SignInAsync(user, isPersistent: false);
|
||||||
return LocalRedirect(model.ReturnUrl);
|
return LocalRedirect(model.ReturnUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("profile")]
|
[HttpGet("profile")]
|
||||||
[HttpGet("settings")]
|
[HttpGet("settings")]
|
||||||
[HttpGet("logout")]
|
[HttpGet("~/connect/logout")]
|
||||||
public IActionResult NotImplemented()
|
public IActionResult NotImplemented()
|
||||||
{
|
{
|
||||||
return RedirectToAction("Index", "Dashboard");
|
return RedirectToAction("Index", "Dashboard");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("logout")]
|
[HttpPost("~/connect/logout")]
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> LogoutPost()
|
public async Task<IActionResult> LogoutPost()
|
||||||
{
|
{
|
||||||
await _signInManager.SignOutAsync();
|
await signInManager.SignOutAsync();
|
||||||
return Redirect("/");
|
return Redirect("/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using Fengling.AuthService.Data;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -11,11 +12,11 @@ namespace Fengling.AuthService.Controllers;
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class AuditLogsController : ControllerBase
|
public class AuditLogsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly PlatformDbContext _context;
|
||||||
private readonly ILogger<AuditLogsController> _logger;
|
private readonly ILogger<AuditLogsController> _logger;
|
||||||
|
|
||||||
public AuditLogsController(
|
public AuditLogsController(
|
||||||
ApplicationDbContext context,
|
PlatformDbContext context,
|
||||||
ILogger<AuditLogsController> logger)
|
ILogger<AuditLogsController> logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
@ -7,15 +9,16 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using OpenIddict.Abstractions;
|
using OpenIddict.Abstractions;
|
||||||
using OpenIddict.Server.AspNetCore;
|
using OpenIddict.Server.AspNetCore;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Fengling.AuthService.Configuration;
|
||||||
using Fengling.AuthService.ViewModels;
|
using Fengling.AuthService.ViewModels;
|
||||||
using Microsoft.AspNetCore;
|
using Microsoft.AspNetCore;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Swashbuckle.AspNetCore.Annotations;
|
||||||
using static OpenIddict.Abstractions.OpenIddictConstants;
|
using static OpenIddict.Abstractions.OpenIddictConstants;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Route("connect")]
|
|
||||||
public class AuthorizationController(
|
public class AuthorizationController(
|
||||||
IOpenIddictApplicationManager applicationManager,
|
IOpenIddictApplicationManager applicationManager,
|
||||||
IOpenIddictAuthorizationManager authorizationManager,
|
IOpenIddictAuthorizationManager authorizationManager,
|
||||||
@ -26,8 +29,99 @@ public class AuthorizationController(
|
|||||||
: Controller
|
: Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
[HttpGet("authorize")]
|
[Authorize, FormValueRequired("submit.Accept")]
|
||||||
[HttpPost("authorize")]
|
[Tags("submit.Accept")]
|
||||||
|
[HttpPost("~/connect/authorize"), ValidateAntiForgeryToken]
|
||||||
|
[SwaggerIgnore]
|
||||||
|
public async Task<IActionResult> Accept()
|
||||||
|
{
|
||||||
|
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||||
|
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
|
||||||
|
|
||||||
|
// Retrieve the profile of the logged in user.
|
||||||
|
var user = await userManager.GetUserAsync(User) ??
|
||||||
|
throw new InvalidOperationException("The user details cannot be retrieved.");
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The user details cannot be retrieved.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the application details from the database.
|
||||||
|
var application = await applicationManager.FindByClientIdAsync(request.ClientId!) ??
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Details concerning the calling client application cannot be found.");
|
||||||
|
|
||||||
|
// Retrieve the permanent authorizations associated with the user and the calling client application.
|
||||||
|
var authorizations = await authorizationManager.FindAsync(
|
||||||
|
subject: await userManager.GetUserIdAsync(user),
|
||||||
|
client: await applicationManager.GetIdAsync(application),
|
||||||
|
status: OpenIddictConstants.Statuses.Valid,
|
||||||
|
type: OpenIddictConstants.AuthorizationTypes.Permanent,
|
||||||
|
scopes: request.GetScopes()).ToListAsync();
|
||||||
|
|
||||||
|
// Note: the same check is already made in the other action but is repeated
|
||||||
|
// here to ensure a malicious user can't abuse this POST-only endpoint and
|
||||||
|
// force it to return a valid response without the external authorization.
|
||||||
|
if (!authorizations.Any() &&
|
||||||
|
await applicationManager.HasConsentTypeAsync(application, OpenIddictConstants.ConsentTypes.External))
|
||||||
|
{
|
||||||
|
return Forbid(
|
||||||
|
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||||
|
properties: new AuthenticationProperties(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.ConsentRequired,
|
||||||
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
|
||||||
|
"The logged in user is not allowed to access this client application."
|
||||||
|
}!));
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
|
||||||
|
|
||||||
|
var principal = result.Principal!;
|
||||||
|
|
||||||
|
// Note: in this sample, the granted scopes match the requested scope
|
||||||
|
// but you may want to allow the user to uncheck specific scopes.
|
||||||
|
// For that, simply restrict the list of scopes before calling SetScopes.
|
||||||
|
principal.SetScopes(request.GetScopes());
|
||||||
|
principal.SetResources(await scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());
|
||||||
|
|
||||||
|
// Automatically create a permanent authorization to avoid requiring explicit consent
|
||||||
|
// for future authorization or token requests containing the same scopes.
|
||||||
|
var authorization = authorizations.LastOrDefault();
|
||||||
|
if (authorization == null)
|
||||||
|
{
|
||||||
|
authorization = await authorizationManager.CreateAsync(
|
||||||
|
principal: principal,
|
||||||
|
subject: await userManager.GetUserIdAsync(user)!,
|
||||||
|
client: await applicationManager.GetIdAsync(application) ?? string.Empty,
|
||||||
|
type: OpenIddictConstants.AuthorizationTypes.Permanent,
|
||||||
|
scopes: principal.GetScopes());
|
||||||
|
}
|
||||||
|
|
||||||
|
principal.SetAuthorizationId(await authorizationManager.GetIdAsync(authorization));
|
||||||
|
|
||||||
|
foreach (var claim in principal.Claims)
|
||||||
|
{
|
||||||
|
claim.SetDestinations(GetDestinations(claim, principal));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
|
||||||
|
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize, FormValueRequired("submit.Deny")]
|
||||||
|
[Tags("submit.Deny")]
|
||||||
|
[SwaggerIgnore]
|
||||||
|
[HttpPost("~/connect/authorize"), ValidateAntiForgeryToken]
|
||||||
|
// Notify OpenIddict that the authorization grant has been denied by the resource owner
|
||||||
|
// to redirect the user agent to the client application using the appropriate response_mode.
|
||||||
|
public IActionResult Deny() => Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("~/connect/authorize")]
|
||||||
|
[HttpPost("~/connect/authorize")]
|
||||||
|
[Tags("Authorize")]
|
||||||
|
[IgnoreAntiforgeryToken]
|
||||||
public async Task<IActionResult> Authorize()
|
public async Task<IActionResult> Authorize()
|
||||||
{
|
{
|
||||||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||||
@ -156,8 +250,10 @@ public class AuthorizationController(
|
|||||||
|
|
||||||
// At this point, no authorization was found in the database and an error must be returned
|
// 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.
|
// if the client application specified prompt=none in the authorization request.
|
||||||
case OpenIddictConstants.ConsentTypes.Explicit when request.HasPromptValue(OpenIddictConstants.PromptValues.None):
|
case OpenIddictConstants.ConsentTypes.Explicit
|
||||||
case OpenIddictConstants.ConsentTypes.Systematic when request.HasPromptValue(OpenIddictConstants.PromptValues.None):
|
when request.HasPromptValue(OpenIddictConstants.PromptValues.None):
|
||||||
|
case OpenIddictConstants.ConsentTypes.Systematic
|
||||||
|
when request.HasPromptValue(OpenIddictConstants.PromptValues.None):
|
||||||
return Forbid(
|
return Forbid(
|
||||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||||
properties: new AuthenticationProperties(new Dictionary<string, string>
|
properties: new AuthenticationProperties(new Dictionary<string, string>
|
||||||
@ -170,13 +266,17 @@ public class AuthorizationController(
|
|||||||
|
|
||||||
// In every other case, render the consent form.
|
// In every other case, render the consent form.
|
||||||
default:
|
default:
|
||||||
return View(new AuthorizeViewModel(await applicationManager.GetDisplayNameAsync(application),request.Scope));
|
return View(new AuthorizeViewModel(await applicationManager.GetDisplayNameAsync(application),
|
||||||
|
request.Scope));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private IEnumerable<string> GetDestinations(Claim claim, ClaimsPrincipal principal)
|
private IEnumerable<string> GetDestinations(Claim claim, ClaimsPrincipal principal)
|
||||||
{
|
{
|
||||||
// Note: by default, claims are NOT automatically included in the access and identity tokens.
|
// Note: by default, claims are NOT automatically included in access and identity tokens.
|
||||||
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
|
// 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.
|
// whether they should be included in access tokens, in identity tokens or in both.
|
||||||
|
|
||||||
@ -214,4 +314,54 @@ public class AuthorizationController(
|
|||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)]
|
||||||
|
[HttpGet("~/connect/userinfo")]
|
||||||
|
public async Task<IActionResult> UserInfo()
|
||||||
|
{
|
||||||
|
var user = await userManager.GetUserAsync(User) ??
|
||||||
|
throw new InvalidOperationException("The user details cannot be retrieved.");
|
||||||
|
|
||||||
|
// 获取用户的角色
|
||||||
|
var roles = await userManager.GetRolesAsync(user);
|
||||||
|
|
||||||
|
// 获取用户的租户信息
|
||||||
|
var tenantInfo = user.TenantInfo;
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new(OpenIddictConstants.Claims.Subject, await userManager.GetUserIdAsync(user)),
|
||||||
|
new(OpenIddictConstants.Claims.Name, user.UserName!),
|
||||||
|
new(OpenIddictConstants.Claims.PreferredUsername, user.UserName!)
|
||||||
|
};
|
||||||
|
if (claims == null) throw new ArgumentNullException(nameof(claims));
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(user.Email))
|
||||||
|
{
|
||||||
|
claims.Add(new(OpenIddictConstants.Claims.Email, user.Email!));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加角色 claims
|
||||||
|
foreach (var role in roles)
|
||||||
|
{
|
||||||
|
claims.Add(new(OpenIddictConstants.Claims.Role, role));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加自定义 tenant 相关 claims
|
||||||
|
claims.Add(new Claim("tenant_id", tenantInfo.TenantId.ToString()));
|
||||||
|
claims.Add(new Claim("tenant_code", tenantInfo.TenantCode));
|
||||||
|
claims.Add(new Claim("tenant_name", tenantInfo.TenantName));
|
||||||
|
|
||||||
|
return Ok(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["sub"] = await userManager.GetUserIdAsync(user),
|
||||||
|
["name"] = user.UserName ?? "Anonymous",
|
||||||
|
["preferred_username"] = user.UserName ?? "Anonymous",
|
||||||
|
["email"] = user.Email ?? "",
|
||||||
|
["role"] = roles.ToArray(),
|
||||||
|
["tenant_id"] = tenantInfo.TenantId.ToString(),
|
||||||
|
["tenant_code"] = tenantInfo?.TenantCode ?? "",
|
||||||
|
["tenant_name"] = tenantInfo?.TenantName ?? ""
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore;
|
using Microsoft.AspNetCore;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
@ -8,6 +10,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using OpenIddict.Abstractions;
|
using OpenIddict.Abstractions;
|
||||||
using OpenIddict.Server.AspNetCore;
|
using OpenIddict.Server.AspNetCore;
|
||||||
using static OpenIddict.Abstractions.OpenIddictConstants;
|
using static OpenIddict.Abstractions.OpenIddictConstants;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
|
|
||||||
@ -43,29 +46,87 @@ public class LogoutController : ControllerBase
|
|||||||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||||
throw new InvalidOperationException("OpenIddict request is null");
|
throw new InvalidOperationException("OpenIddict request is null");
|
||||||
|
|
||||||
|
// 标准做法:先尝试从 id_token_hint 中提取客户端信息
|
||||||
|
string? clientId = request.ClientId;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(request.IdTokenHint))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 从 id_token_hint 中提取 client_id (azp claim 或 aud claim)
|
||||||
|
var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
|
||||||
|
if (principal != null)
|
||||||
|
{
|
||||||
|
// 尝试从 azp (authorized party) claim 获取
|
||||||
|
clientId = principal.GetClaim(Claims.AuthorizedParty);
|
||||||
|
|
||||||
|
// 如果没有 azp,尝试从 aud (audience) claim 获取
|
||||||
|
if (string.IsNullOrEmpty(clientId))
|
||||||
|
{
|
||||||
|
clientId = principal.GetClaim(Claims.Audience);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to extract client_id from id_token_hint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行登出
|
||||||
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
|
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
await _signInManager.SignOutAsync();
|
await _signInManager.SignOutAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.ClientId != null)
|
// 处理 post_logout_redirect_uri
|
||||||
|
if (!string.IsNullOrEmpty(clientId))
|
||||||
{
|
{
|
||||||
var application = await _applicationManager.FindByClientIdAsync(request.ClientId);
|
var application = await _applicationManager.FindByClientIdAsync(clientId);
|
||||||
if (application != null)
|
if (application != null)
|
||||||
{
|
{
|
||||||
var postLogoutRedirectUri = await _applicationManager.GetPostLogoutRedirectUrisAsync(application);
|
var registeredUris = await _applicationManager.GetPostLogoutRedirectUrisAsync(application);
|
||||||
|
|
||||||
|
// 如果提供了 post_logout_redirect_uri,验证它是否在注册的 URI 列表中
|
||||||
if (!string.IsNullOrEmpty(request.PostLogoutRedirectUri))
|
if (!string.IsNullOrEmpty(request.PostLogoutRedirectUri))
|
||||||
{
|
{
|
||||||
if (postLogoutRedirectUri.Contains(request.PostLogoutRedirectUri))
|
if (registeredUris.Contains(request.PostLogoutRedirectUri))
|
||||||
{
|
{
|
||||||
return Redirect(request.PostLogoutRedirectUri);
|
// 如果提供了 state,需要附加到重定向 URI
|
||||||
|
var redirectUri = request.PostLogoutRedirectUri;
|
||||||
|
if (!string.IsNullOrEmpty(request.State))
|
||||||
|
{
|
||||||
|
var separator = redirectUri.Contains('?') ? "&" : "?";
|
||||||
|
redirectUri = $"{redirectUri}{separator}state={Uri.EscapeDataString(request.State)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redirect(redirectUri);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Post-logout redirect URI {Uri} is not registered for client {ClientId}",
|
||||||
|
request.PostLogoutRedirectUri,
|
||||||
|
clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果没有提供 post_logout_redirect_uri,使用第一个注册的 URI
|
||||||
|
var defaultUri = registeredUris.FirstOrDefault();
|
||||||
|
if (!string.IsNullOrEmpty(defaultUri))
|
||||||
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Using default post-logout redirect URI for client {ClientId}",
|
||||||
|
clientId);
|
||||||
|
return Redirect(defaultUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果无法确定重定向地址,返回默认页面
|
||||||
return Redirect("/");
|
return Redirect("/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,6 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using OpenIddict.Abstractions;
|
using OpenIddict.Abstractions;
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
@ -14,16 +10,13 @@ namespace Fengling.AuthService.Controllers;
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class OAuthClientsController : ControllerBase
|
public class OAuthClientsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
|
||||||
private readonly IOpenIddictApplicationManager _applicationManager;
|
private readonly IOpenIddictApplicationManager _applicationManager;
|
||||||
private readonly ILogger<OAuthClientsController> _logger;
|
private readonly ILogger<OAuthClientsController> _logger;
|
||||||
|
|
||||||
public OAuthClientsController(
|
public OAuthClientsController(
|
||||||
ApplicationDbContext context,
|
|
||||||
IOpenIddictApplicationManager applicationManager,
|
IOpenIddictApplicationManager applicationManager,
|
||||||
ILogger<OAuthClientsController> logger)
|
ILogger<OAuthClientsController> logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
|
||||||
_applicationManager = applicationManager;
|
_applicationManager = applicationManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@ -33,54 +26,60 @@ public class OAuthClientsController : ControllerBase
|
|||||||
[FromQuery] int page = 1,
|
[FromQuery] int page = 1,
|
||||||
[FromQuery] int pageSize = 10,
|
[FromQuery] int pageSize = 10,
|
||||||
[FromQuery] string? displayName = null,
|
[FromQuery] string? displayName = null,
|
||||||
[FromQuery] string? clientId = null,
|
[FromQuery] string? clientId = null)
|
||||||
[FromQuery] string? status = null)
|
|
||||||
{
|
{
|
||||||
var query = _context.OAuthApplications.AsQueryable();
|
var applications = _applicationManager.ListAsync();
|
||||||
|
var clientList = new List<object>();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(displayName))
|
await foreach (var application in applications)
|
||||||
{
|
{
|
||||||
query = query.Where(c => c.DisplayName.Contains(displayName));
|
var clientIdValue = await _applicationManager.GetClientIdAsync(application);
|
||||||
|
var displayNameValue = await _applicationManager.GetDisplayNameAsync(application);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(displayName) && !displayNameValue.Contains(displayName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(clientId) && !clientIdValue.Contains(clientId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var clientType = await _applicationManager.GetClientTypeAsync(application);
|
||||||
|
var consentType = await _applicationManager.GetConsentTypeAsync(application);
|
||||||
|
var permissions = await _applicationManager.GetPermissionsAsync(application);
|
||||||
|
var redirectUrisStrings = await _applicationManager.GetRedirectUrisAsync(application);
|
||||||
|
var postLogoutRedirectUrisStrings = await _applicationManager.GetPostLogoutRedirectUrisAsync(application);
|
||||||
|
var redirectUris = redirectUrisStrings;
|
||||||
|
var postLogoutRedirectUris = postLogoutRedirectUrisStrings;
|
||||||
|
|
||||||
|
clientList.Add(new
|
||||||
|
{
|
||||||
|
id = application,
|
||||||
|
clientId = clientIdValue,
|
||||||
|
displayName = displayNameValue,
|
||||||
|
redirectUris = redirectUris.Select(u => u.ToString()).ToArray(),
|
||||||
|
postLogoutRedirectUris = postLogoutRedirectUris.Select(u => u.ToString()).ToArray(),
|
||||||
|
scopes = permissions
|
||||||
|
.Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.Scope))
|
||||||
|
.Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.Scope.Length)),
|
||||||
|
grantTypes = permissions
|
||||||
|
.Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.GrantType))
|
||||||
|
.Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.GrantType.Length)),
|
||||||
|
clientType = clientType?.ToString(),
|
||||||
|
consentType = consentType?.ToString(),
|
||||||
|
status = "active",
|
||||||
|
permissions
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(clientId))
|
var sortedClients = clientList
|
||||||
{
|
.OrderByDescending(c => (c as dynamic).clientId)
|
||||||
query = query.Where(c => c.ClientId.Contains(clientId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(status))
|
|
||||||
{
|
|
||||||
query = query.Where(c => c.Status == status);
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalCount = await query.CountAsync();
|
|
||||||
var clients = await query
|
|
||||||
.OrderByDescending(c => c.CreatedAt)
|
|
||||||
.Skip((page - 1) * pageSize)
|
.Skip((page - 1) * pageSize)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.ToListAsync();
|
.ToList();
|
||||||
|
|
||||||
var result = clients.Select(c => new
|
|
||||||
{
|
|
||||||
id = c.Id,
|
|
||||||
clientId = c.ClientId,
|
|
||||||
displayName = c.DisplayName,
|
|
||||||
redirectUris = c.RedirectUris,
|
|
||||||
postLogoutRedirectUris = c.PostLogoutRedirectUris,
|
|
||||||
scopes = c.Scopes,
|
|
||||||
grantTypes = c.GrantTypes,
|
|
||||||
clientType = c.ClientType,
|
|
||||||
consentType = c.ConsentType,
|
|
||||||
status = c.Status,
|
|
||||||
description = c.Description,
|
|
||||||
createdAt = c.CreatedAt,
|
|
||||||
updatedAt = c.UpdatedAt,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
items = result,
|
items = sortedClients,
|
||||||
totalCount,
|
totalCount = clientList.Count,
|
||||||
page,
|
page,
|
||||||
pageSize
|
pageSize
|
||||||
});
|
});
|
||||||
@ -127,36 +126,46 @@ public class OAuthClientsController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<ActionResult<OAuthApplication>> GetClient(long id)
|
public async Task<ActionResult<object>> GetClient(string id)
|
||||||
{
|
{
|
||||||
var client = await _context.OAuthApplications.FindAsync(id);
|
var application = await _applicationManager.FindByIdAsync(id);
|
||||||
if (client == null)
|
if (application == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clientIdValue = await _applicationManager.GetClientIdAsync(application);
|
||||||
|
var displayNameValue = await _applicationManager.GetDisplayNameAsync(application);
|
||||||
|
var clientType = await _applicationManager.GetClientTypeAsync(application);
|
||||||
|
var consentType = await _applicationManager.GetConsentTypeAsync(application);
|
||||||
|
var permissions = await _applicationManager.GetPermissionsAsync(application);
|
||||||
|
var redirectUris = await _applicationManager.GetRedirectUrisAsync(application);
|
||||||
|
var postLogoutRedirectUris = await _applicationManager.GetPostLogoutRedirectUrisAsync(application);
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
id = client.Id,
|
id = id,
|
||||||
clientId = client.ClientId,
|
clientId = clientIdValue,
|
||||||
displayName = client.DisplayName,
|
displayName = displayNameValue,
|
||||||
redirectUris = client.RedirectUris,
|
redirectUris = redirectUris.Select(u => u.ToString()).ToArray(),
|
||||||
postLogoutRedirectUris = client.PostLogoutRedirectUris,
|
postLogoutRedirectUris = postLogoutRedirectUris.Select(u => u.ToString()).ToArray(),
|
||||||
scopes = client.Scopes,
|
scopes = permissions
|
||||||
grantTypes = client.GrantTypes,
|
.Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.Scope))
|
||||||
clientType = client.ClientType,
|
.Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.Scope.Length)),
|
||||||
consentType = client.ConsentType,
|
grantTypes = permissions
|
||||||
status = client.Status,
|
.Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.GrantType))
|
||||||
description = client.Description,
|
.Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.GrantType.Length)),
|
||||||
createdAt = client.CreatedAt,
|
clientType = clientType?.ToString(),
|
||||||
updatedAt = client.UpdatedAt,
|
consentType = consentType?.ToString(),
|
||||||
|
status = "active",
|
||||||
|
permissions
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<ActionResult<object>> CreateClient([FromBody] CreateOAuthClientDto dto)
|
public async Task<ActionResult<object>> CreateClient([FromBody] CreateOAuthClientDto dto)
|
||||||
{
|
{
|
||||||
var existingClient = await _context.OAuthApplications.FirstOrDefaultAsync(c => c.ClientId == dto.ClientId);
|
var existingClient = await _applicationManager.FindByClientIdAsync(dto.ClientId);
|
||||||
if (existingClient != null)
|
if (existingClient != null)
|
||||||
{
|
{
|
||||||
return BadRequest(new { message = "Client ID 已存在", clientId = dto.ClientId });
|
return BadRequest(new { message = "Client ID 已存在", clientId = dto.ClientId });
|
||||||
@ -168,9 +177,16 @@ public class OAuthClientsController : ControllerBase
|
|||||||
{
|
{
|
||||||
ClientId = dto.ClientId,
|
ClientId = dto.ClientId,
|
||||||
ClientSecret = clientSecret,
|
ClientSecret = clientSecret,
|
||||||
DisplayName = dto.DisplayName
|
DisplayName = dto.DisplayName,
|
||||||
|
ClientType = string.IsNullOrEmpty(dto.ClientType) ? "confidential" : dto.ClientType,
|
||||||
|
ConsentType = string.IsNullOrEmpty(dto.ConsentType) ? "explicit" : dto.ConsentType,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Authorization);
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.EndSession);
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Token);
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Introspection);
|
||||||
|
|
||||||
foreach (var uri in (dto.RedirectUris ?? Array.Empty<string>()).Where(u => Uri.TryCreate(u, UriKind.Absolute, out _)))
|
foreach (var uri in (dto.RedirectUris ?? Array.Empty<string>()).Where(u => Uri.TryCreate(u, UriKind.Absolute, out _)))
|
||||||
{
|
{
|
||||||
descriptor.RedirectUris.Add(new Uri(uri));
|
descriptor.RedirectUris.Add(new Uri(uri));
|
||||||
@ -183,205 +199,196 @@ public class OAuthClientsController : ControllerBase
|
|||||||
|
|
||||||
foreach (var grantType in dto.GrantTypes ?? Array.Empty<string>())
|
foreach (var grantType in dto.GrantTypes ?? Array.Empty<string>())
|
||||||
{
|
{
|
||||||
descriptor.Permissions.Add(grantType);
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.GrantType + grantType);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var scope in dto.Scopes ?? Array.Empty<string>())
|
foreach (var scope in dto.Scopes ?? Array.Empty<string>())
|
||||||
{
|
{
|
||||||
descriptor.Permissions.Add(scope);
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.Scope + scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _applicationManager.CreateAsync(descriptor);
|
var application = await _applicationManager.CreateAsync(descriptor);
|
||||||
|
var applicationId = await _applicationManager.GetIdAsync(application);
|
||||||
|
|
||||||
var client = new OAuthApplication
|
return CreatedAtAction(nameof(GetClient), new { id = applicationId }, new
|
||||||
{
|
{
|
||||||
ClientId = dto.ClientId,
|
id = applicationId,
|
||||||
ClientSecret = clientSecret,
|
clientId = dto.ClientId,
|
||||||
DisplayName = dto.DisplayName,
|
clientSecret = clientSecret,
|
||||||
RedirectUris = dto.RedirectUris ?? Array.Empty<string>(),
|
displayName = dto.DisplayName,
|
||||||
PostLogoutRedirectUris = dto.PostLogoutRedirectUris ?? Array.Empty<string>(),
|
status = "active"
|
||||||
Scopes = dto.Scopes ?? new[] { "openid", "profile", "email", "api" },
|
|
||||||
GrantTypes = dto.GrantTypes ?? new[] { "authorization_code", "refresh_token" },
|
|
||||||
ClientType = dto.ClientType ?? "confidential",
|
|
||||||
ConsentType = dto.ConsentType ?? "explicit",
|
|
||||||
Status = dto.Status ?? "active",
|
|
||||||
Description = dto.Description,
|
|
||||||
CreatedAt = DateTime.UtcNow,
|
|
||||||
};
|
|
||||||
|
|
||||||
_context.OAuthApplications.Add(client);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
await CreateAuditLog("oauth", "create", "OAuthClient", client.Id, client.DisplayName, null, SerializeToJson(dto));
|
|
||||||
|
|
||||||
return CreatedAtAction(nameof(GetClient), new { id = client.Id }, new
|
|
||||||
{
|
|
||||||
client.Id,
|
|
||||||
client.ClientId,
|
|
||||||
client.ClientSecret,
|
|
||||||
client.DisplayName,
|
|
||||||
client.Status,
|
|
||||||
client.CreatedAt
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("{id}/generate-secret")]
|
[HttpPost("{id}/generate-secret")]
|
||||||
public async Task<ActionResult<object>> GenerateSecret(long id)
|
public async Task<ActionResult<object>> GenerateSecret(string id)
|
||||||
{
|
{
|
||||||
var client = await _context.OAuthApplications.FindAsync(id);
|
var application = await _applicationManager.FindByIdAsync(id);
|
||||||
if (client == null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
var newSecret = GenerateSecureSecret();
|
|
||||||
client.ClientSecret = newSecret;
|
|
||||||
client.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var application = await _applicationManager.FindByClientIdAsync(client.ClientId);
|
|
||||||
if (application != null)
|
|
||||||
{
|
|
||||||
var descriptor = new OpenIddictApplicationDescriptor
|
|
||||||
{
|
|
||||||
ClientId = client.ClientId,
|
|
||||||
ClientSecret = newSecret,
|
|
||||||
DisplayName = client.DisplayName
|
|
||||||
};
|
|
||||||
|
|
||||||
await _applicationManager.UpdateAsync(application, descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
await CreateAuditLog("oauth", "generate_secret", "OAuthClient", client.Id, client.DisplayName, "[REDACTED]", "[REDACTED]");
|
|
||||||
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
clientId = client.ClientId,
|
|
||||||
clientSecret = newSecret,
|
|
||||||
message = "新密钥已生成,请妥善保管,刷新后将无法再次查看"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{id}/toggle-status")]
|
|
||||||
public async Task<ActionResult<object>> ToggleStatus(long id)
|
|
||||||
{
|
|
||||||
var client = await _context.OAuthApplications.FindAsync(id);
|
|
||||||
if (client == null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldStatus = client.Status;
|
|
||||||
client.Status = client.Status == "active" ? "inactive" : "active";
|
|
||||||
client.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
await CreateAuditLog("oauth", "toggle_status", "OAuthClient", client.Id, client.DisplayName, oldStatus, client.Status);
|
|
||||||
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
clientId = client.ClientId,
|
|
||||||
oldStatus,
|
|
||||||
newStatus = client.Status,
|
|
||||||
message = $"客户端状态已从 {oldStatus} 更改为 {client.Status}"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
public async Task<IActionResult> UpdateClient(long id, [FromBody] UpdateOAuthClientDto dto)
|
|
||||||
{
|
|
||||||
var client = await _context.OAuthApplications.FindAsync(id);
|
|
||||||
if (client == null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
var application = await _applicationManager.FindByClientIdAsync(client.ClientId);
|
|
||||||
if (application == null)
|
if (application == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clientIdValue = await _applicationManager.GetClientIdAsync(application);
|
||||||
|
var displayNameValue = await _applicationManager.GetDisplayNameAsync(application);
|
||||||
|
var clientType = await _applicationManager.GetClientTypeAsync(application);
|
||||||
|
var consentType = await _applicationManager.GetConsentTypeAsync(application);
|
||||||
|
var permissions = await _applicationManager.GetPermissionsAsync(application);
|
||||||
|
var redirectUris = await _applicationManager.GetRedirectUrisAsync(application);
|
||||||
|
var postLogoutRedirectUris = await _applicationManager.GetPostLogoutRedirectUrisAsync(application);
|
||||||
|
|
||||||
|
var newSecret = GenerateSecureSecret();
|
||||||
|
|
||||||
var descriptor = new OpenIddictApplicationDescriptor
|
var descriptor = new OpenIddictApplicationDescriptor
|
||||||
{
|
{
|
||||||
ClientId = client.ClientId,
|
ClientId = clientIdValue,
|
||||||
ClientSecret = client.ClientSecret,
|
ClientSecret = newSecret,
|
||||||
DisplayName = dto.DisplayName ?? client.DisplayName
|
DisplayName = displayNameValue,
|
||||||
|
ClientType = clientType,
|
||||||
|
ConsentType = consentType,
|
||||||
};
|
};
|
||||||
|
|
||||||
var redirectUris = dto.RedirectUris ?? client.RedirectUris;
|
foreach (var permission in permissions)
|
||||||
foreach (var uri in redirectUris.Where(u => Uri.TryCreate(u, UriKind.Absolute, out _)))
|
|
||||||
{
|
{
|
||||||
descriptor.RedirectUris.Add(new Uri(uri));
|
descriptor.Permissions.Add(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
var postLogoutUris = dto.PostLogoutRedirectUris ?? client.PostLogoutRedirectUris;
|
foreach (var uriString in redirectUris)
|
||||||
foreach (var uri in postLogoutUris.Where(u => Uri.TryCreate(u, UriKind.Absolute, out _)))
|
|
||||||
{
|
{
|
||||||
descriptor.PostLogoutRedirectUris.Add(new Uri(uri));
|
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
|
||||||
|
{
|
||||||
|
descriptor.RedirectUris.Add(uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var grantTypes = dto.GrantTypes ?? client.GrantTypes;
|
foreach (var uriString in postLogoutRedirectUris)
|
||||||
foreach (var grantType in grantTypes)
|
|
||||||
{
|
{
|
||||||
descriptor.Permissions.Add(grantType);
|
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
|
||||||
|
{
|
||||||
|
descriptor.PostLogoutRedirectUris.Add(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
var scopes = dto.Scopes ?? client.Scopes;
|
|
||||||
foreach (var scope in scopes)
|
|
||||||
{
|
|
||||||
descriptor.Permissions.Add(scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _applicationManager.UpdateAsync(application, descriptor);
|
await _applicationManager.UpdateAsync(application, descriptor);
|
||||||
|
|
||||||
client.DisplayName = dto.DisplayName ?? client.DisplayName;
|
return Ok(new
|
||||||
client.RedirectUris = redirectUris;
|
{
|
||||||
client.PostLogoutRedirectUris = postLogoutUris;
|
clientId = clientIdValue,
|
||||||
client.Scopes = scopes;
|
clientSecret = newSecret,
|
||||||
client.GrantTypes = grantTypes;
|
message = "新密钥已生成,请妥善保管,刷新后将无法再次查看"
|
||||||
client.ClientType = dto.ClientType ?? client.ClientType;
|
});
|
||||||
client.ConsentType = dto.ConsentType ?? client.ConsentType;
|
|
||||||
client.Status = dto.Status ?? client.Status;
|
|
||||||
client.Description = dto.Description ?? client.Description;
|
|
||||||
client.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
await CreateAuditLog("oauth", "update", "OAuthClient", client.Id, client.DisplayName, null, SerializeToJson(client));
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> DeleteClient(long id)
|
public async Task<IActionResult> DeleteClient(string id)
|
||||||
{
|
{
|
||||||
var client = await _context.OAuthApplications.FindAsync(id);
|
var application = await _applicationManager.FindByIdAsync(id);
|
||||||
if (client == null)
|
if (application == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clientIdValue = await _applicationManager.GetClientIdAsync(application);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
|
||||||
var application = await _applicationManager.FindByClientIdAsync(client.ClientId);
|
|
||||||
if (application != null)
|
|
||||||
{
|
{
|
||||||
await _applicationManager.DeleteAsync(application);
|
await _applicationManager.DeleteAsync(application);
|
||||||
_logger.LogInformation("Deleted OpenIddict application {ClientId}", client.ClientId);
|
_logger.LogInformation("Deleted OpenIddict application {ClientId}", clientIdValue);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, "Failed to delete OpenIddict application for client {ClientId}", client.ClientId);
|
_logger.LogWarning(ex, "Failed to delete OpenIddict application for client {ClientId}", clientIdValue);
|
||||||
|
return BadRequest(new { message = ex.Message });
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.OAuthApplications.Remove(client);
|
return NoContent();
|
||||||
await _context.SaveChangesAsync();
|
}
|
||||||
|
|
||||||
await CreateAuditLog("oauth", "delete", "OAuthClient", client.Id, client.DisplayName, SerializeToJson(client));
|
[HttpPut("{id}")]
|
||||||
|
public async Task<IActionResult> UpdateClient(string id, [FromBody] UpdateOAuthClientDto dto)
|
||||||
|
{
|
||||||
|
var application = await _applicationManager.FindByIdAsync(id);
|
||||||
|
if (application == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientIdValue = await _applicationManager.GetClientIdAsync(application);
|
||||||
|
var displayNameValue = await _applicationManager.GetDisplayNameAsync(application);
|
||||||
|
var clientType = await _applicationManager.GetClientTypeAsync(application);
|
||||||
|
var consentType = await _applicationManager.GetConsentTypeAsync(application);
|
||||||
|
var redirectUris = await _applicationManager.GetRedirectUrisAsync(application);
|
||||||
|
var postLogoutRedirectUris = await _applicationManager.GetPostLogoutRedirectUrisAsync(application);
|
||||||
|
var existingPermissions = await _applicationManager.GetPermissionsAsync(application);
|
||||||
|
|
||||||
|
var descriptor = new OpenIddictApplicationDescriptor
|
||||||
|
{
|
||||||
|
ClientId = clientIdValue,
|
||||||
|
DisplayName = dto.DisplayName ?? displayNameValue,
|
||||||
|
ClientType = string.IsNullOrEmpty(dto.ClientType) ? clientType?.ToString() : dto.ClientType,
|
||||||
|
ConsentType = string.IsNullOrEmpty(dto.ConsentType) ? consentType?.ToString() : dto.ConsentType,
|
||||||
|
};
|
||||||
|
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Authorization);
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.EndSession);
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Token);
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Introspection);
|
||||||
|
|
||||||
|
if (dto.RedirectUris != null)
|
||||||
|
{
|
||||||
|
foreach (var uri in dto.RedirectUris.Where(u => Uri.TryCreate(u, UriKind.Absolute, out _)))
|
||||||
|
{
|
||||||
|
descriptor.RedirectUris.Add(new Uri(uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var uriString in redirectUris)
|
||||||
|
{
|
||||||
|
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
|
||||||
|
{
|
||||||
|
descriptor.RedirectUris.Add(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.PostLogoutRedirectUris != null)
|
||||||
|
{
|
||||||
|
foreach (var uri in dto.PostLogoutRedirectUris.Where(u => Uri.TryCreate(u, UriKind.Absolute, out _)))
|
||||||
|
{
|
||||||
|
descriptor.PostLogoutRedirectUris.Add(new Uri(uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var uriString in postLogoutRedirectUris)
|
||||||
|
{
|
||||||
|
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
|
||||||
|
{
|
||||||
|
descriptor.PostLogoutRedirectUris.Add(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var grantTypes = dto.GrantTypes ?? existingPermissions
|
||||||
|
.Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.GrantType))
|
||||||
|
.Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.GrantType.Length));
|
||||||
|
|
||||||
|
var scopes = dto.Scopes ?? existingPermissions
|
||||||
|
.Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.Scope))
|
||||||
|
.Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.Scope.Length));
|
||||||
|
|
||||||
|
foreach (var grantType in grantTypes)
|
||||||
|
{
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.GrantType + grantType);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var scope in scopes)
|
||||||
|
{
|
||||||
|
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Prefixes.Scope + scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _applicationManager.UpdateAsync(application, descriptor);
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
@ -392,38 +399,6 @@ public class OAuthClientsController : ControllerBase
|
|||||||
var bytes = RandomNumberGenerator.GetBytes(length);
|
var bytes = RandomNumberGenerator.GetBytes(length);
|
||||||
return new string(bytes.Select(b => chars[b % chars.Length]).ToArray());
|
return new string(bytes.Select(b => chars[b % chars.Length]).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId, string? targetName, string? oldValue = null, string? newValue = null)
|
|
||||||
{
|
|
||||||
var userName = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.Identity?.Name ?? "system";
|
|
||||||
var tenantId = User.FindFirstValue("TenantId");
|
|
||||||
|
|
||||||
var log = new AuditLog
|
|
||||||
{
|
|
||||||
Operator = userName,
|
|
||||||
TenantId = tenantId,
|
|
||||||
Operation = operation,
|
|
||||||
Action = action,
|
|
||||||
TargetType = targetType,
|
|
||||||
TargetId = targetId,
|
|
||||||
TargetName = targetName,
|
|
||||||
IpAddress = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
|
|
||||||
Status = "success",
|
|
||||||
OldValue = oldValue,
|
|
||||||
NewValue = newValue,
|
|
||||||
};
|
|
||||||
|
|
||||||
_context.AuditLogs.Add(log);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string SerializeToJson(object obj)
|
|
||||||
{
|
|
||||||
return System.Text.Json.JsonSerializer.Serialize(obj, new System.Text.Json.JsonSerializerOptions
|
|
||||||
{
|
|
||||||
WriteIndented = false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreateOAuthClientDto
|
public class CreateOAuthClientDto
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -13,13 +15,13 @@ namespace Fengling.AuthService.Controllers;
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class RolesController : ControllerBase
|
public class RolesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly PlatformDbContext _context;
|
||||||
private readonly RoleManager<ApplicationRole> _roleManager;
|
private readonly RoleManager<ApplicationRole> _roleManager;
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly ILogger<RolesController> _logger;
|
private readonly ILogger<RolesController> _logger;
|
||||||
|
|
||||||
public RolesController(
|
public RolesController(
|
||||||
ApplicationDbContext context,
|
PlatformDbContext context,
|
||||||
RoleManager<ApplicationRole> roleManager,
|
RoleManager<ApplicationRole> roleManager,
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
ILogger<RolesController> logger)
|
ILogger<RolesController> logger)
|
||||||
@ -122,8 +124,7 @@ public class RolesController : ControllerBase
|
|||||||
id = u.Id,
|
id = u.Id,
|
||||||
userName = u.UserName,
|
userName = u.UserName,
|
||||||
email = u.Email,
|
email = u.Email,
|
||||||
realName = u.RealName,
|
tenantId = u.TenantInfo.TenantId,
|
||||||
tenantId = u.TenantInfo.Id,
|
|
||||||
roles = await _userManager.GetRolesAsync(u),
|
roles = await _userManager.GetRolesAsync(u),
|
||||||
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
|
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
|
||||||
createdAt = u.CreatedTime,
|
createdAt = u.CreatedTime,
|
||||||
|
|||||||
@ -1,26 +1,25 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OpenIddict.Abstractions;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class StatsController : ControllerBase
|
public class StatsController(
|
||||||
|
PlatformDbContext context,
|
||||||
|
IOpenIddictApplicationManager applicationManager,
|
||||||
|
ILogger<StatsController> logger,
|
||||||
|
PlatformDbContext platformDbContext)
|
||||||
|
: ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
|
||||||
private readonly ILogger<StatsController> _logger;
|
|
||||||
|
|
||||||
public StatsController(
|
|
||||||
ApplicationDbContext context,
|
|
||||||
ILogger<StatsController> logger)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("dashboard")]
|
[HttpGet("dashboard")]
|
||||||
public async Task<ActionResult<object>> GetDashboardStats()
|
public async Task<ActionResult<object>> GetDashboardStats()
|
||||||
@ -28,10 +27,10 @@ public class StatsController : ControllerBase
|
|||||||
var today = DateTime.UtcNow.Date;
|
var today = DateTime.UtcNow.Date;
|
||||||
var tomorrow = today.AddDays(1);
|
var tomorrow = today.AddDays(1);
|
||||||
|
|
||||||
var userCount = await _context.Users.CountAsync(u => !u.IsDeleted);
|
var userCount = await context.Users.CountAsync(u => !u.IsDeleted);
|
||||||
var tenantCount = await _context.Tenants.CountAsync(t => !t.IsDeleted);
|
var tenantCount = await platformDbContext.Tenants.CountAsync(t => !t.IsDeleted);
|
||||||
var oauthClientCount = await _context.OAuthApplications.CountAsync();
|
var oauthClientCount = await CountOAuthClientsAsync();
|
||||||
var todayAccessCount = await _context.AccessLogs
|
var todayAccessCount = await context.AccessLogs
|
||||||
.CountAsync(l => l.CreatedAt >= today && l.CreatedAt < tomorrow);
|
.CountAsync(l => l.CreatedAt >= today && l.CreatedAt < tomorrow);
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
@ -43,6 +42,17 @@ public class StatsController : ControllerBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> CountOAuthClientsAsync()
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
var applications = applicationManager.ListAsync();
|
||||||
|
await foreach (var _ in applications)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("system")]
|
[HttpGet("system")]
|
||||||
public ActionResult<object> GetSystemStats()
|
public ActionResult<object> GetSystemStats()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,54 +1,49 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class TenantsController : ControllerBase
|
public class TenantsController(
|
||||||
{
|
PlatformDbContext context,
|
||||||
private readonly ApplicationDbContext _context;
|
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
|
||||||
private readonly ILogger<TenantsController> _logger;
|
|
||||||
|
|
||||||
public TenantsController(
|
|
||||||
ApplicationDbContext context,
|
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
ILogger<TenantsController> logger)
|
ILogger<TenantsController> logger,
|
||||||
{
|
PlatformDbContext platformDbContext)
|
||||||
_context = context;
|
: ControllerBase
|
||||||
_userManager = userManager;
|
{
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<object>> GetTenants(
|
public async Task<ActionResult<object>> GetTenants(
|
||||||
[FromQuery] int page = 1,
|
[FromQuery] int page = 1,
|
||||||
[FromQuery] int pageSize = 10,
|
[FromQuery] int pageSize = 10,
|
||||||
[FromQuery] string? name = null,
|
[FromQuery] string? name = null,
|
||||||
[FromQuery] string? tenantId = null,
|
[FromQuery] string? tenantCode = null,
|
||||||
[FromQuery] string? status = null)
|
[FromQuery] TenantStatus? status = null)
|
||||||
{
|
{
|
||||||
var query = _context.Tenants.AsQueryable();
|
var query = platformDbContext.Tenants.AsQueryable();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(name))
|
if (!string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
query = query.Where(t => t.Name.Contains(name));
|
query = query.Where(t => t.Name.Contains(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tenantId))
|
if (!string.IsNullOrEmpty(tenantCode))
|
||||||
{
|
{
|
||||||
query = query.Where(t => t.TenantId.Contains(tenantId));
|
query = query.Where(t => t.TenantCode.Contains(tenantCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(status))
|
if (status.HasValue)
|
||||||
{
|
{
|
||||||
query = query.Where(t => t.Status == status);
|
query = query.Where(t => t.Status == status);
|
||||||
}
|
}
|
||||||
@ -64,11 +59,11 @@ public class TenantsController : ControllerBase
|
|||||||
|
|
||||||
foreach (var tenant in tenants)
|
foreach (var tenant in tenants)
|
||||||
{
|
{
|
||||||
var userCount = await _context.Users.CountAsync(u => u.TenantInfo.Id == tenant.Id && !u.IsDeleted);
|
var userCount = await context.Users.CountAsync(u => u.TenantInfo.TenantId == tenant.Id && !u.IsDeleted);
|
||||||
result.Add(new
|
result.Add(new
|
||||||
{
|
{
|
||||||
id = tenant.Id,
|
id = tenant.Id,
|
||||||
tenantId = tenant.TenantId,
|
tenantId = tenant.Id,
|
||||||
name = tenant.Name,
|
name = tenant.Name,
|
||||||
contactName = tenant.ContactName,
|
contactName = tenant.ContactName,
|
||||||
contactEmail = tenant.ContactEmail,
|
contactEmail = tenant.ContactEmail,
|
||||||
@ -94,7 +89,7 @@ public class TenantsController : ControllerBase
|
|||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<ActionResult<Tenant>> GetTenant(long id)
|
public async Task<ActionResult<Tenant>> GetTenant(long id)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FindAsync(id);
|
var tenant = await platformDbContext.Tenants.FindAsync(id);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -103,7 +98,7 @@ public class TenantsController : ControllerBase
|
|||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
id = tenant.Id,
|
id = tenant.Id,
|
||||||
tenantId = tenant.TenantId,
|
tenantId = tenant.Id,
|
||||||
name = tenant.Name,
|
name = tenant.Name,
|
||||||
contactName = tenant.ContactName,
|
contactName = tenant.ContactName,
|
||||||
contactEmail = tenant.ContactEmail,
|
contactEmail = tenant.ContactEmail,
|
||||||
@ -118,16 +113,21 @@ public class TenantsController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{tenantId}/users")]
|
[HttpGet("{tenantId}/users")]
|
||||||
public async Task<ActionResult<List<object>>> GetTenantUsers(string tenantId)
|
public async Task<ActionResult<List<object>>> GetTenantUsers(long tenantId)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
|
var tenant = await platformDbContext.Tenants
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == tenantId);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var users = await _context.Users
|
var users = await context.Users
|
||||||
.Where(u => u.TenantInfo.Id == tenant.Id && !u.IsDeleted)
|
.Where(u =>
|
||||||
|
u.TenantInfo != null
|
||||||
|
&&
|
||||||
|
u.TenantInfo.TenantId == tenant.Id
|
||||||
|
&& !u.IsDeleted)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
var result = users.Select(async u => new
|
var result = users.Select(async u => new
|
||||||
@ -135,9 +135,8 @@ public class TenantsController : ControllerBase
|
|||||||
id = u.Id,
|
id = u.Id,
|
||||||
userName = u.UserName,
|
userName = u.UserName,
|
||||||
email = u.Email,
|
email = u.Email,
|
||||||
realName = u.RealName,
|
tenantId = u.TenantInfo?.TenantId,
|
||||||
tenantId = u.TenantInfo.Id,
|
roles = await userManager.GetRolesAsync(u),
|
||||||
roles = await _userManager.GetRolesAsync(u),
|
|
||||||
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
|
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
|
||||||
createdAt = u.CreatedTime,
|
createdAt = u.CreatedTime,
|
||||||
});
|
});
|
||||||
@ -146,15 +145,16 @@ public class TenantsController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{tenantId}/roles")]
|
[HttpGet("{tenantId}/roles")]
|
||||||
public async Task<ActionResult<List<object>>> GetTenantRoles(string tenantId)
|
public async Task<ActionResult<List<object>>> GetTenantRoles(long tenantId)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
|
var tenant = await platformDbContext.Tenants
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == tenantId);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var roles = await _context.Roles
|
var roles = await context.Roles
|
||||||
.Where(r => r.TenantId == tenant.Id)
|
.Where(r => r.TenantId == tenant.Id)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
@ -169,9 +169,10 @@ public class TenantsController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{tenantId}/settings")]
|
[HttpGet("{tenantId}/settings")]
|
||||||
public async Task<ActionResult<TenantSettings>> GetTenantSettings(string tenantId)
|
public async Task<ActionResult<TenantSettings>> GetTenantSettings(long tenantId)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
|
var tenant = await platformDbContext.Tenants
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == tenantId);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -191,15 +192,16 @@ public class TenantsController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{tenantId}/settings")]
|
[HttpPut("{tenantId}/settings")]
|
||||||
public async Task<IActionResult> UpdateTenantSettings(string tenantId, TenantSettings settings)
|
public async Task<IActionResult> UpdateTenantSettings(long tenantId, TenantSettings settings)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
|
var tenant = await platformDbContext.Tenants.FirstOrDefaultAsync(t => t.Id == tenantId);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
await CreateAuditLog("tenant", "update", "TenantSettings", tenant.Id, tenant.TenantId, null, JsonSerializer.Serialize(settings));
|
await CreateAuditLog("tenant", "update", "TenantSettings", tenant.Id, tenant.Name, null,
|
||||||
|
JsonSerializer.Serialize(settings));
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
@ -209,22 +211,23 @@ public class TenantsController : ControllerBase
|
|||||||
{
|
{
|
||||||
var tenant = new Tenant
|
var tenant = new Tenant
|
||||||
{
|
{
|
||||||
TenantId = dto.TenantId,
|
TenantCode = dto.TenantCode,
|
||||||
Name = dto.Name,
|
Name = dto.TenantName,
|
||||||
ContactName = dto.ContactName,
|
ContactName = dto.ContactName,
|
||||||
ContactEmail = dto.ContactEmail,
|
ContactEmail = dto.ContactEmail,
|
||||||
ContactPhone = dto.ContactPhone,
|
ContactPhone = dto.ContactPhone,
|
||||||
MaxUsers = dto.MaxUsers,
|
MaxUsers = dto.MaxUsers,
|
||||||
Description = dto.Description,
|
Description = dto.Description,
|
||||||
Status = dto.Status,
|
|
||||||
ExpiresAt = dto.ExpiresAt,
|
ExpiresAt = dto.ExpiresAt,
|
||||||
|
Status = TenantStatus.Active,
|
||||||
CreatedAt = DateTime.UtcNow,
|
CreatedAt = DateTime.UtcNow,
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.Tenants.Add(tenant);
|
platformDbContext.Tenants.Add(tenant);
|
||||||
await _context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
await CreateAuditLog("tenant", "create", "Tenant", tenant.Id, tenant.TenantId, null, JsonSerializer.Serialize(dto));
|
await CreateAuditLog("tenant", "create", "Tenant", tenant.Id, tenant.TenantCode,
|
||||||
|
null, JsonSerializer.Serialize(dto));
|
||||||
|
|
||||||
return CreatedAtAction(nameof(GetTenant), new { id = tenant.Id }, tenant);
|
return CreatedAtAction(nameof(GetTenant), new { id = tenant.Id }, tenant);
|
||||||
}
|
}
|
||||||
@ -232,27 +235,24 @@ public class TenantsController : ControllerBase
|
|||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
public async Task<IActionResult> UpdateTenant(long id, UpdateTenantDto dto)
|
public async Task<IActionResult> UpdateTenant(long id, UpdateTenantDto dto)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FindAsync(id);
|
var tenant = await platformDbContext.Tenants.FindAsync(id);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldValue = JsonSerializer.Serialize(tenant);
|
var oldValue = JsonSerializer.Serialize(tenant);
|
||||||
|
|
||||||
tenant.Name = dto.Name;
|
tenant.Name = dto.Name;
|
||||||
tenant.ContactName = dto.ContactName;
|
tenant.ContactName = dto.ContactName;
|
||||||
tenant.ContactEmail = dto.ContactEmail;
|
tenant.ContactEmail = dto.ContactEmail;
|
||||||
tenant.ContactPhone = dto.ContactPhone;
|
tenant.ContactPhone = dto.ContactPhone;
|
||||||
tenant.MaxUsers = dto.MaxUsers;
|
|
||||||
tenant.Description = dto.Description;
|
|
||||||
tenant.Status = dto.Status;
|
|
||||||
tenant.ExpiresAt = dto.ExpiresAt;
|
|
||||||
tenant.UpdatedAt = DateTime.UtcNow;
|
tenant.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
await CreateAuditLog("tenant", "update", "Tenant", tenant.Id, tenant.TenantId, oldValue, JsonSerializer.Serialize(tenant));
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
await CreateAuditLog("tenant", "update", "Tenant", tenant.Id, tenant.Name, oldValue,
|
||||||
|
JsonSerializer.Serialize(tenant));
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
@ -260,7 +260,7 @@ public class TenantsController : ControllerBase
|
|||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> DeleteTenant(long id)
|
public async Task<IActionResult> DeleteTenant(long id)
|
||||||
{
|
{
|
||||||
var tenant = await _context.Tenants.FindAsync(id);
|
var tenant = await platformDbContext.Tenants.FindAsync(id);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -268,7 +268,7 @@ public class TenantsController : ControllerBase
|
|||||||
|
|
||||||
var oldValue = JsonSerializer.Serialize(tenant);
|
var oldValue = JsonSerializer.Serialize(tenant);
|
||||||
|
|
||||||
var users = await _context.Users.Where(u => u.TenantInfo.Id == tenant.Id).ToListAsync();
|
var users = await context.Users.Where(u => u.TenantInfo.TenantId == tenant.Id).ToListAsync();
|
||||||
foreach (var user in users)
|
foreach (var user in users)
|
||||||
{
|
{
|
||||||
user.IsDeleted = true;
|
user.IsDeleted = true;
|
||||||
@ -276,14 +276,16 @@ public class TenantsController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
tenant.IsDeleted = true;
|
tenant.IsDeleted = true;
|
||||||
await _context.SaveChangesAsync();
|
tenant.UpdatedAt = DateTime.UtcNow;
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
await CreateAuditLog("tenant", "delete", "Tenant", tenant.Id, tenant.TenantId, oldValue);
|
await CreateAuditLog("tenant", "delete", "Tenant", tenant.Id, tenant.Name, oldValue);
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId, string? targetName, string? oldValue = null, string? newValue = null)
|
private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId,
|
||||||
|
string? targetName, string? oldValue = null, string? newValue = null)
|
||||||
{
|
{
|
||||||
var userName = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.Identity?.Name ?? "system";
|
var userName = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.Identity?.Name ?? "system";
|
||||||
var tenantId = User.FindFirstValue("TenantId");
|
var tenantId = User.FindFirstValue("TenantId");
|
||||||
@ -303,23 +305,21 @@ public class TenantsController : ControllerBase
|
|||||||
NewValue = newValue,
|
NewValue = newValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.AuditLogs.Add(log);
|
context.AuditLogs.Add(log);
|
||||||
await _context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreateTenantDto
|
public record CreateTenantDto(
|
||||||
{
|
string TenantCode,
|
||||||
public string TenantId { get; set; } = string.Empty;
|
string TenantName,
|
||||||
public string Name { get; set; } = string.Empty;
|
string ContactName,
|
||||||
public string ContactName { get; set; } = string.Empty;
|
string ContactEmail,
|
||||||
public string ContactEmail { get; set; } = string.Empty;
|
string ContactPhone,
|
||||||
public string? ContactPhone { get; set; }
|
int? MaxUsers,
|
||||||
public int? MaxUsers { get; set; }
|
string? Description,
|
||||||
public string? Description { get; set; }
|
string Status,
|
||||||
public string Status { get; set; } = "active";
|
DateTime? ExpiresAt);
|
||||||
public DateTime? ExpiresAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UpdateTenantDto
|
public class UpdateTenantDto
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@ -23,14 +25,13 @@ public class TokenController(
|
|||||||
ILogger<TokenController> logger)
|
ILogger<TokenController> logger)
|
||||||
: ControllerBase
|
: ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILogger<TokenController> _logger = logger;
|
|
||||||
|
|
||||||
[HttpPost("token")]
|
[HttpPost("token")]
|
||||||
public async Task<IActionResult> Exchange()
|
public async Task<IActionResult> Exchange()
|
||||||
{
|
{
|
||||||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||||
throw new InvalidOperationException("OpenIddict request is null");
|
throw new InvalidOperationException("OpenIddict request is null");
|
||||||
var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
|
var result = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
if (request.IsAuthorizationCodeGrantType())
|
if (request.IsAuthorizationCodeGrantType())
|
||||||
{
|
{
|
||||||
@ -96,9 +97,9 @@ public class TokenController(
|
|||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
{
|
{
|
||||||
new(Claims.Subject, await userManager.GetUserIdAsync(user)),
|
new(Claims.Subject, await userManager.GetUserIdAsync(user)),
|
||||||
new(Claims.Name, await userManager.GetUserNameAsync(user)),
|
new(Claims.Name, await userManager.GetUserNameAsync(user) ?? throw new InvalidOperationException()),
|
||||||
new(Claims.Email, await userManager.GetEmailAsync(user) ?? ""),
|
new(Claims.Email, await userManager.GetEmailAsync(user) ?? ""),
|
||||||
new("tenant_id", user.TenantInfo.Id.ToString())
|
new("tenant_id", user.TenantInfo.TenantId.ToString())
|
||||||
};
|
};
|
||||||
|
|
||||||
var roles = await userManager.GetRolesAsync(user);
|
var roles = await userManager.GetRolesAsync(user);
|
||||||
@ -110,6 +111,12 @@ public class TokenController(
|
|||||||
var identity = new ClaimsIdentity(claims, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
var identity = new ClaimsIdentity(claims, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||||
var principal = new ClaimsPrincipal(identity);
|
var principal = new ClaimsPrincipal(identity);
|
||||||
|
|
||||||
|
// 设置 Claim Destinations
|
||||||
|
foreach (var claim in principal.Claims)
|
||||||
|
{
|
||||||
|
claim.SetDestinations(GetDestinations(claim, principal));
|
||||||
|
}
|
||||||
|
|
||||||
principal.SetScopes(request.GetScopes());
|
principal.SetScopes(request.GetScopes());
|
||||||
principal.SetResources(await scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());
|
principal.SetResources(await scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());
|
||||||
principal.SetAuthorizationId(await authorizationManager.GetIdAsync(authorization));
|
principal.SetAuthorizationId(await authorizationManager.GetIdAsync(authorization));
|
||||||
@ -199,8 +206,14 @@ public class TokenController(
|
|||||||
|
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
|
// 明确处理租户 ID - 这是业务关键信息
|
||||||
|
case "tenant_id":
|
||||||
|
yield return OpenIddictConstants.Destinations.AccessToken;
|
||||||
|
yield break;
|
||||||
|
|
||||||
// Never include the security stamp in the access and identity tokens, as it's a secret value.
|
// Never include the security stamp in the access and identity tokens, as it's a secret value.
|
||||||
case "AspNet.Identity.SecurityStamp": yield break;
|
case "AspNet.Identity.SecurityStamp":
|
||||||
|
yield break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
yield return OpenIddictConstants.Destinations.AccessToken;
|
yield return OpenIddictConstants.Destinations.AccessToken;
|
||||||
@ -233,9 +246,9 @@ public class TokenController(
|
|||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
{
|
{
|
||||||
new(Claims.Subject, await userManager.GetUserIdAsync(user)),
|
new(Claims.Subject, await userManager.GetUserIdAsync(user)),
|
||||||
new(Claims.Name, await userManager.GetUserNameAsync(user)),
|
new(Claims.Name, await userManager.GetUserNameAsync(user) ?? string.Empty),
|
||||||
new(Claims.Email, await userManager.GetEmailAsync(user) ?? ""),
|
new(Claims.Email, await userManager.GetEmailAsync(user) ?? ""),
|
||||||
new("tenant_id", user.TenantInfo.Id.ToString())
|
new("tenant_id", user.TenantInfo.TenantId.ToString())
|
||||||
};
|
};
|
||||||
|
|
||||||
var roles = await userManager.GetRolesAsync(user);
|
var roles = await userManager.GetRolesAsync(user);
|
||||||
@ -247,6 +260,12 @@ public class TokenController(
|
|||||||
var identity = new ClaimsIdentity(claims, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
var identity = new ClaimsIdentity(claims, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||||
var principal = new ClaimsPrincipal(identity);
|
var principal = new ClaimsPrincipal(identity);
|
||||||
|
|
||||||
|
// 设置 Claim Destinations
|
||||||
|
foreach (var claim in principal.Claims)
|
||||||
|
{
|
||||||
|
claim.SetDestinations(GetDestinations(claim, principal));
|
||||||
|
}
|
||||||
|
|
||||||
principal.SetScopes(request.GetScopes());
|
principal.SetScopes(request.GetScopes());
|
||||||
principal.SetResources(await scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());
|
principal.SetResources(await scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());
|
||||||
|
|
||||||
|
|||||||
@ -1,34 +1,25 @@
|
|||||||
using Fengling.AuthService.Data;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
|
||||||
|
|
||||||
namespace Fengling.AuthService.Controllers;
|
namespace Fengling.AuthService.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class UsersController : ControllerBase
|
public class UsersController(
|
||||||
{
|
|
||||||
private readonly ApplicationDbContext _context;
|
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
|
||||||
private readonly RoleManager<ApplicationRole> _roleManager;
|
|
||||||
private readonly ILogger<UsersController> _logger;
|
|
||||||
|
|
||||||
public UsersController(
|
|
||||||
ApplicationDbContext context,
|
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
RoleManager<ApplicationRole> roleManager,
|
RoleManager<ApplicationRole> roleManager,
|
||||||
ILogger<UsersController> logger)
|
ILogger<UsersController> logger,
|
||||||
{
|
PlatformDbContext platformDbContext)
|
||||||
_context = context;
|
: ControllerBase
|
||||||
_userManager = userManager;
|
{
|
||||||
_roleManager = roleManager;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<object>> GetUsers(
|
public async Task<ActionResult<object>> GetUsers(
|
||||||
@ -36,9 +27,9 @@ public class UsersController : ControllerBase
|
|||||||
[FromQuery] int pageSize = 10,
|
[FromQuery] int pageSize = 10,
|
||||||
[FromQuery] string? userName = null,
|
[FromQuery] string? userName = null,
|
||||||
[FromQuery] string? email = null,
|
[FromQuery] string? email = null,
|
||||||
[FromQuery] string? tenantId = null)
|
[FromQuery] string? tenantCode = null)
|
||||||
{
|
{
|
||||||
var query = _context.Users.AsQueryable();
|
var query = platformDbContext.Users.AsQueryable();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(userName))
|
if (!string.IsNullOrEmpty(userName))
|
||||||
{
|
{
|
||||||
@ -50,9 +41,9 @@ public class UsersController : ControllerBase
|
|||||||
query = query.Where(u => u.Email != null && u.Email.Contains(email));
|
query = query.Where(u => u.Email != null && u.Email.Contains(email));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tenantId))
|
if (!string.IsNullOrEmpty(tenantCode))
|
||||||
{
|
{
|
||||||
query = query.Where(u => u.TenantInfo.Id.ToString() == tenantId);
|
query = query.Where(u => u.TenantInfo.TenantCode == tenantCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalCount = await query.CountAsync();
|
var totalCount = await query.CountAsync();
|
||||||
@ -67,10 +58,8 @@ public class UsersController : ControllerBase
|
|||||||
id = u.Id,
|
id = u.Id,
|
||||||
userName = u.UserName,
|
userName = u.UserName,
|
||||||
email = u.Email,
|
email = u.Email,
|
||||||
realName = u.RealName,
|
tenantId = u.TenantInfo.TenantId,
|
||||||
phone = u.Phone,
|
roles = (await userManager.GetRolesAsync(u)).ToList(),
|
||||||
tenantId = u.TenantInfo.Id,
|
|
||||||
roles = (await _userManager.GetRolesAsync(u)).ToList(),
|
|
||||||
emailConfirmed = u.EmailConfirmed,
|
emailConfirmed = u.EmailConfirmed,
|
||||||
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
|
isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow,
|
||||||
createdAt = u.CreatedTime,
|
createdAt = u.CreatedTime,
|
||||||
@ -88,22 +77,20 @@ public class UsersController : ControllerBase
|
|||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<ActionResult<object>> GetUser(long id)
|
public async Task<ActionResult<object>> GetUser(long id)
|
||||||
{
|
{
|
||||||
var user = await _context.Users.FindAsync(id);
|
var user = await platformDbContext.Users.FindAsync(id);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var roles = await _userManager.GetRolesAsync(user);
|
var roles = await userManager.GetRolesAsync(user);
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
id = user.Id,
|
id = user.Id,
|
||||||
userName = user.UserName,
|
userName = user.UserName,
|
||||||
email = user.Email,
|
email = user.Email,
|
||||||
realName = user.RealName,
|
tenantId = user.TenantInfo.TenantId,
|
||||||
phone = user.Phone,
|
|
||||||
tenantId = user.TenantInfo.Id,
|
|
||||||
roles,
|
roles,
|
||||||
emailConfirmed = user.EmailConfirmed,
|
emailConfirmed = user.EmailConfirmed,
|
||||||
isActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow,
|
isActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow,
|
||||||
@ -115,11 +102,11 @@ public class UsersController : ControllerBase
|
|||||||
public async Task<ActionResult<ApplicationUser>> CreateUser(CreateUserDto dto)
|
public async Task<ActionResult<ApplicationUser>> CreateUser(CreateUserDto dto)
|
||||||
{
|
{
|
||||||
var tenantId = dto.TenantId ?? 0;
|
var tenantId = dto.TenantId ?? 0;
|
||||||
Tenant tenant = null;
|
Tenant? tenant = null;
|
||||||
|
|
||||||
if (tenantId != 0)
|
if (tenantId != 0)
|
||||||
{
|
{
|
||||||
tenant = await _context.Tenants.FindAsync(tenantId);
|
tenant = await platformDbContext.Tenants.FindAsync(tenantId);
|
||||||
if (tenant == null)
|
if (tenant == null)
|
||||||
{
|
{
|
||||||
return BadRequest("Invalid tenant ID");
|
return BadRequest("Invalid tenant ID");
|
||||||
@ -130,35 +117,33 @@ public class UsersController : ControllerBase
|
|||||||
{
|
{
|
||||||
UserName = dto.UserName,
|
UserName = dto.UserName,
|
||||||
Email = dto.Email,
|
Email = dto.Email,
|
||||||
RealName = dto.RealName,
|
TenantInfo = new TenantInfo(tenant!),
|
||||||
Phone = dto.Phone,
|
|
||||||
TenantInfo = new TenantInfo(tenantId, tenant?.TenantId ?? "default", tenant?.Name ?? "默认租户"),
|
|
||||||
EmailConfirmed = dto.EmailConfirmed,
|
EmailConfirmed = dto.EmailConfirmed,
|
||||||
CreatedTime = DateTime.UtcNow,
|
CreatedTime = DateTimeOffset.UtcNow,
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = await _userManager.CreateAsync(user, dto.Password);
|
var result = await userManager.CreateAsync(user, dto.Password);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
return BadRequest(result.Errors);
|
return BadRequest(result.Errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dto.RoleIds != null && dto.RoleIds.Any())
|
if (dto.RoleIds.Any())
|
||||||
{
|
{
|
||||||
foreach (var roleId in dto.RoleIds)
|
foreach (var roleId in dto.RoleIds)
|
||||||
{
|
{
|
||||||
var role = await _roleManager.FindByIdAsync(roleId.ToString());
|
var role = await roleManager.FindByIdAsync(roleId.ToString());
|
||||||
if (role != null)
|
if (role != null)
|
||||||
{
|
{
|
||||||
await _userManager.AddToRoleAsync(user, role.Name!);
|
await userManager.AddToRoleAsync(user, role.Name!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dto.IsActive)
|
if (!dto.IsActive)
|
||||||
{
|
{
|
||||||
await _userManager.SetLockoutEnabledAsync(user, true);
|
await userManager.SetLockoutEnabledAsync(user, true);
|
||||||
await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.MaxValue);
|
await userManager.SetLockoutEndDateAsync(user, DateTimeOffset.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
await CreateAuditLog("user", "create", "User", user.Id, user.UserName, null, SerializeToJson(dto));
|
await CreateAuditLog("user", "create", "User", user.Id, user.UserName, null, SerializeToJson(dto));
|
||||||
@ -169,7 +154,7 @@ public class UsersController : ControllerBase
|
|||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
public async Task<IActionResult> UpdateUser(long id, UpdateUserDto dto)
|
public async Task<IActionResult> UpdateUser(long id, UpdateUserDto dto)
|
||||||
{
|
{
|
||||||
var user = await _context.Users.FindAsync(id);
|
var user = await platformDbContext.Users.FindAsync(id);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -178,23 +163,21 @@ public class UsersController : ControllerBase
|
|||||||
var oldValue = System.Text.Json.JsonSerializer.Serialize(user);
|
var oldValue = System.Text.Json.JsonSerializer.Serialize(user);
|
||||||
|
|
||||||
user.Email = dto.Email;
|
user.Email = dto.Email;
|
||||||
user.RealName = dto.RealName;
|
|
||||||
user.Phone = dto.Phone;
|
|
||||||
user.EmailConfirmed = dto.EmailConfirmed;
|
user.EmailConfirmed = dto.EmailConfirmed;
|
||||||
user.UpdatedTime = DateTime.UtcNow;
|
user.UpdatedTime = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
if (dto.IsActive)
|
if (dto.IsActive)
|
||||||
{
|
{
|
||||||
await _userManager.SetLockoutEnabledAsync(user, false);
|
await userManager.SetLockoutEnabledAsync(user, false);
|
||||||
await _userManager.SetLockoutEndDateAsync(user, null);
|
await userManager.SetLockoutEndDateAsync(user, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _userManager.SetLockoutEnabledAsync(user, true);
|
await userManager.SetLockoutEnabledAsync(user, true);
|
||||||
await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.MaxValue);
|
await userManager.SetLockoutEndDateAsync(user, DateTimeOffset.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await platformDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
await CreateAuditLog("user", "update", "User", user.Id, user.UserName, oldValue, System.Text.Json.JsonSerializer.Serialize(user));
|
await CreateAuditLog("user", "update", "User", user.Id, user.UserName, oldValue, System.Text.Json.JsonSerializer.Serialize(user));
|
||||||
|
|
||||||
@ -204,14 +187,14 @@ public class UsersController : ControllerBase
|
|||||||
[HttpPut("{id}/password")]
|
[HttpPut("{id}/password")]
|
||||||
public async Task<IActionResult> ResetPassword(long id, ResetPasswordDto dto)
|
public async Task<IActionResult> ResetPassword(long id, ResetPasswordDto dto)
|
||||||
{
|
{
|
||||||
var user = await _userManager.FindByIdAsync(id.ToString());
|
var user = await userManager.FindByIdAsync(id.ToString());
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
|
var token = await userManager.GeneratePasswordResetTokenAsync(user);
|
||||||
var result = await _userManager.ResetPasswordAsync(user, token, dto.NewPassword);
|
var result = await userManager.ResetPasswordAsync(user, token, dto.NewPassword);
|
||||||
|
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
@ -226,7 +209,7 @@ public class UsersController : ControllerBase
|
|||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> DeleteUser(long id)
|
public async Task<IActionResult> DeleteUser(long id)
|
||||||
{
|
{
|
||||||
var user = await _context.Users.FindAsync(id);
|
var user = await platformDbContext.Users.FindAsync(id);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -235,7 +218,7 @@ public class UsersController : ControllerBase
|
|||||||
var oldValue = System.Text.Json.JsonSerializer.Serialize(user);
|
var oldValue = System.Text.Json.JsonSerializer.Serialize(user);
|
||||||
user.IsDeleted = true;
|
user.IsDeleted = true;
|
||||||
user.UpdatedTime = DateTime.UtcNow;
|
user.UpdatedTime = DateTime.UtcNow;
|
||||||
await _context.SaveChangesAsync();
|
await platformDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
await CreateAuditLog("user", "delete", "User", user.Id, user.UserName, oldValue);
|
await CreateAuditLog("user", "delete", "User", user.Id, user.UserName, oldValue);
|
||||||
|
|
||||||
@ -262,8 +245,8 @@ public class UsersController : ControllerBase
|
|||||||
NewValue = newValue,
|
NewValue = newValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
_context.AuditLogs.Add(log);
|
platformDbContext.AuditLogs.Add(log);
|
||||||
await _context.SaveChangesAsync();
|
await platformDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SerializeToJson(object obj)
|
private string SerializeToJson(object obj)
|
||||||
|
|||||||
@ -1,106 +0,0 @@
|
|||||||
using Fengling.AuthService.Models;
|
|
||||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Data;
|
|
||||||
|
|
||||||
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
|
|
||||||
{
|
|
||||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
|
||||||
: base(options)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbSet<OAuthApplication> OAuthApplications { get; set; }
|
|
||||||
public DbSet<Tenant> Tenants { get; set; }
|
|
||||||
public DbSet<AccessLog> AccessLogs { get; set; }
|
|
||||||
public DbSet<AuditLog> AuditLogs { get; set; }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
|
||||||
{
|
|
||||||
base.OnModelCreating(builder);
|
|
||||||
|
|
||||||
builder.Entity<ApplicationUser>(entity =>
|
|
||||||
{
|
|
||||||
entity.Property(e => e.RealName).HasMaxLength(100);
|
|
||||||
entity.Property(e => e.Phone).HasMaxLength(20);
|
|
||||||
entity.HasIndex(e => e.Phone).IsUnique();
|
|
||||||
|
|
||||||
entity.OwnsOne(e => e.TenantInfo, navigationBuilder =>
|
|
||||||
{
|
|
||||||
navigationBuilder.Property(e => e.Id).HasColumnName("TenantId");
|
|
||||||
navigationBuilder.Property(e => e.TenantId).HasColumnName("TenantCode");
|
|
||||||
navigationBuilder.Property(e => e.Name).HasColumnName("TenantName");
|
|
||||||
navigationBuilder.WithOwner();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<ApplicationRole>(entity =>
|
|
||||||
{
|
|
||||||
entity.Property(e => e.Description).HasMaxLength(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<OAuthApplication>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.HasIndex(e => e.ClientId).IsUnique();
|
|
||||||
entity.Property(e => e.ClientId).HasMaxLength(100);
|
|
||||||
entity.Property(e => e.ClientSecret).HasMaxLength(200);
|
|
||||||
entity.Property(e => e.DisplayName).HasMaxLength(100);
|
|
||||||
entity.Property(e => e.ClientType).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.ConsentType).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.Status).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.Description).HasMaxLength(500);
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<Tenant>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.HasIndex(e => e.TenantId).IsUnique();
|
|
||||||
entity.Property(e => e.TenantId).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.Name).HasMaxLength(100);
|
|
||||||
entity.Property(e => e.ContactName).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.ContactEmail).HasMaxLength(100);
|
|
||||||
entity.Property(e => e.ContactPhone).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.Status).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.Description).HasMaxLength(500);
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<AccessLog>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.HasIndex(e => e.CreatedAt);
|
|
||||||
entity.HasIndex(e => e.UserName);
|
|
||||||
entity.HasIndex(e => e.TenantId);
|
|
||||||
entity.HasIndex(e => e.Action);
|
|
||||||
entity.HasIndex(e => e.Status);
|
|
||||||
entity.Property(e => e.UserName).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.TenantId).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.Action).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.Resource).HasMaxLength(200);
|
|
||||||
entity.Property(e => e.Method).HasMaxLength(10);
|
|
||||||
entity.Property(e => e.IpAddress).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.UserAgent).HasMaxLength(500);
|
|
||||||
entity.Property(e => e.Status).HasMaxLength(20);
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Entity<AuditLog>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.HasIndex(e => e.CreatedAt);
|
|
||||||
entity.HasIndex(e => e.Operator);
|
|
||||||
entity.HasIndex(e => e.TenantId);
|
|
||||||
entity.HasIndex(e => e.Operation);
|
|
||||||
entity.HasIndex(e => e.Action);
|
|
||||||
entity.Property(e => e.Operator).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.TenantId).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.Operation).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.Action).HasMaxLength(20);
|
|
||||||
entity.Property(e => e.TargetType).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.TargetName).HasMaxLength(100);
|
|
||||||
entity.Property(e => e.IpAddress).HasMaxLength(50);
|
|
||||||
entity.Property(e => e.Description).HasMaxLength(500);
|
|
||||||
entity.Property(e => e.Status).HasMaxLength(20);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
using Fengling.AuthService.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Design;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Data;
|
|
||||||
|
|
||||||
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
|
|
||||||
{
|
|
||||||
public ApplicationDbContext CreateDbContext(string[] args)
|
|
||||||
{
|
|
||||||
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
|
||||||
optionsBuilder.UseNpgsql("Host=192.168.100.10;Port=5432;Database=fengling_auth;Username=movingsam;Password=sl52788542");
|
|
||||||
|
|
||||||
return new ApplicationDbContext(optionsBuilder.Options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
150
Data/SeedData.cs
150
Data/SeedData.cs
@ -1,150 +0,0 @@
|
|||||||
using Fengling.AuthService.Models;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Data;
|
|
||||||
|
|
||||||
public static class SeedData
|
|
||||||
{
|
|
||||||
public static async Task Initialize(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
using var scope = serviceProvider.CreateScope();
|
|
||||||
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
|
||||||
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
|
||||||
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<ApplicationRole>>();
|
|
||||||
|
|
||||||
await context.Database.EnsureCreatedAsync();
|
|
||||||
|
|
||||||
var defaultTenant = await context.Tenants
|
|
||||||
.AsNoTracking()
|
|
||||||
.FirstOrDefaultAsync(t => t.TenantId == "default");
|
|
||||||
if (defaultTenant == null)
|
|
||||||
{
|
|
||||||
defaultTenant = new Tenant
|
|
||||||
{
|
|
||||||
TenantId = "default",
|
|
||||||
Name = "默认租户",
|
|
||||||
ContactName = "系统管理员",
|
|
||||||
ContactEmail = "admin@fengling.local",
|
|
||||||
ContactPhone = "13800138000",
|
|
||||||
MaxUsers = 1000,
|
|
||||||
Description = "系统默认租户",
|
|
||||||
Status = "active",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
context.Tenants.Add(defaultTenant);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var adminRole = await roleManager.FindByNameAsync("Admin");
|
|
||||||
if (adminRole == null)
|
|
||||||
{
|
|
||||||
adminRole = new ApplicationRole
|
|
||||||
{
|
|
||||||
Name = "Admin",
|
|
||||||
DisplayName = "管理员",
|
|
||||||
Description = "System administrator",
|
|
||||||
TenantId = defaultTenant.Id,
|
|
||||||
IsSystem = true,
|
|
||||||
Permissions = new List<string>
|
|
||||||
{
|
|
||||||
"user.manage", "user.view",
|
|
||||||
"role.manage", "role.view",
|
|
||||||
"tenant.manage", "tenant.view",
|
|
||||||
"oauth.manage", "oauth.view",
|
|
||||||
"log.view", "system.config"
|
|
||||||
},
|
|
||||||
CreatedTime = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
await roleManager.CreateAsync(adminRole);
|
|
||||||
}
|
|
||||||
|
|
||||||
var userRole = await roleManager.FindByNameAsync("User");
|
|
||||||
if (userRole == null)
|
|
||||||
{
|
|
||||||
userRole = new ApplicationRole
|
|
||||||
{
|
|
||||||
Name = "User",
|
|
||||||
DisplayName = "普通用户",
|
|
||||||
Description = "Regular user",
|
|
||||||
TenantId = defaultTenant.Id,
|
|
||||||
IsSystem = true,
|
|
||||||
Permissions = new List<string> { "user.view" },
|
|
||||||
CreatedTime = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
await roleManager.CreateAsync(userRole);
|
|
||||||
}
|
|
||||||
|
|
||||||
var adminUser = await userManager.FindByNameAsync("admin");
|
|
||||||
if (adminUser == null)
|
|
||||||
{
|
|
||||||
adminUser = new ApplicationUser
|
|
||||||
{
|
|
||||||
UserName = "admin",
|
|
||||||
Email = "admin@fengling.local",
|
|
||||||
RealName = "系统管理员",
|
|
||||||
Phone = "13800138000",
|
|
||||||
TenantInfo = new TenantInfo(defaultTenant.Id, defaultTenant.TenantId, defaultTenant.Name),
|
|
||||||
EmailConfirmed = true,
|
|
||||||
IsDeleted = false,
|
|
||||||
CreatedTime = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await userManager.CreateAsync(adminUser, "Admin@123");
|
|
||||||
if (result.Succeeded)
|
|
||||||
{
|
|
||||||
await userManager.AddToRoleAsync(adminUser, "Admin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var testUser = await userManager.FindByNameAsync("testuser");
|
|
||||||
if (testUser == null)
|
|
||||||
{
|
|
||||||
testUser = new ApplicationUser
|
|
||||||
{
|
|
||||||
UserName = "testuser",
|
|
||||||
Email = "test@fengling.local",
|
|
||||||
RealName = "测试用户",
|
|
||||||
Phone = "13900139000",
|
|
||||||
TenantInfo = new TenantInfo(defaultTenant.Id, defaultTenant.TenantId, defaultTenant.Name),
|
|
||||||
EmailConfirmed = true,
|
|
||||||
IsDeleted = false,
|
|
||||||
CreatedTime = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await userManager.CreateAsync(testUser, "Test@123");
|
|
||||||
if (result.Succeeded)
|
|
||||||
{
|
|
||||||
await userManager.AddToRoleAsync(testUser, "User");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var consoleClient = await context.OAuthApplications
|
|
||||||
.FirstOrDefaultAsync(c => c.ClientId == "fengling-console");
|
|
||||||
if (consoleClient == null)
|
|
||||||
{
|
|
||||||
consoleClient = new OAuthApplication
|
|
||||||
{
|
|
||||||
ClientId = "fengling-console",
|
|
||||||
ClientSecret = null,
|
|
||||||
DisplayName = "Fengling Console",
|
|
||||||
RedirectUris = new[] {
|
|
||||||
"http://localhost:5777/auth/callback",
|
|
||||||
"https://console.fengling.local/auth/callback"
|
|
||||||
},
|
|
||||||
PostLogoutRedirectUris = new[] {
|
|
||||||
"http://localhost:5777/",
|
|
||||||
"https://console.fengling.local/"
|
|
||||||
},
|
|
||||||
Scopes = new[] { "api", "offline_access", "openid", "profile", "email" },
|
|
||||||
GrantTypes = new[] { "authorization_code", "refresh_token" },
|
|
||||||
ClientType = "public",
|
|
||||||
ConsentType = "implicit",
|
|
||||||
Status = "active",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
context.OAuthApplications.Add(consoleClient);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,6 +6,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NetCorePal.Extensions.AspNetCore" />
|
||||||
|
<PackageReference Include="OpenIddict.Quartz" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@ -32,4 +34,9 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Fengling.Platform\Fengling.Platform.Domain\Fengling.Platform.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\Fengling.Platform\Fengling.Platform.Infrastructure\Fengling.Platform.Infrastructure.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
639
Migrations/20260205165820_InitialCreate.Designer.cs
generated
639
Migrations/20260205165820_InitialCreate.Designer.cs
generated
@ -1,639 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Fengling.AuthService.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(ApplicationDbContext))]
|
|
||||||
[Migration("20260205165820_InitialCreate")]
|
|
||||||
partial class InitialCreate
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "10.0.2")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.AccessLog", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Action")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<int>("Duration")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("ErrorMessage")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("Method")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)");
|
|
||||||
|
|
||||||
b.Property<string>("RequestData")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Resource")
|
|
||||||
.HasMaxLength(200)
|
|
||||||
.HasColumnType("character varying(200)");
|
|
||||||
|
|
||||||
b.Property<string>("ResponseData")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("TenantId")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("UserAgent")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("Action");
|
|
||||||
|
|
||||||
b.HasIndex("CreatedAt");
|
|
||||||
|
|
||||||
b.HasIndex("Status");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
|
||||||
|
|
||||||
b.HasIndex("UserName");
|
|
||||||
|
|
||||||
b.ToTable("AccessLogs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.ApplicationRole", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedTime")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(200)
|
|
||||||
.HasColumnType("character varying(200)");
|
|
||||||
|
|
||||||
b.Property<string>("DisplayName")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<bool>("IsSystem")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<List<string>>("Permissions")
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.Property<long?>("TenantId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedName")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("RoleNameIndex");
|
|
||||||
|
|
||||||
b.ToTable("AspNetRoles", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<int>("AccessFailedCount")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedTime")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Email")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<bool>("IsDeleted")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<bool>("LockoutEnabled")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedUserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<string>("PasswordHash")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Phone")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("PhoneNumber")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<bool>("PhoneNumberConfirmed")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<string>("RealName")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("SecurityStamp")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<bool>("TwoFactorEnabled")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedTime")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedEmail")
|
|
||||||
.HasDatabaseName("EmailIndex");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedUserName")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("UserNameIndex");
|
|
||||||
|
|
||||||
b.HasIndex("Phone")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("AspNetUsers", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.AuditLog", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Action")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("ErrorMessage")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("NewValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("OldValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Operation")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("Operator")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<long?>("TargetId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<string>("TargetName")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("TargetType")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("TenantId")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("Action");
|
|
||||||
|
|
||||||
b.HasIndex("CreatedAt");
|
|
||||||
|
|
||||||
b.HasIndex("Operation");
|
|
||||||
|
|
||||||
b.HasIndex("Operator");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
|
||||||
|
|
||||||
b.ToTable("AuditLogs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.OAuthApplication", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ClientId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("ClientSecret")
|
|
||||||
.HasMaxLength(200)
|
|
||||||
.HasColumnType("character varying(200)");
|
|
||||||
|
|
||||||
b.Property<string>("ClientType")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("ConsentType")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("DisplayName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("GrantTypes")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("PostLogoutRedirectUris")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("RedirectUris")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("Scopes")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ClientId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("OAuthApplications");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.Tenant", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ContactEmail")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("ContactName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("ContactPhone")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("ExpiresAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<bool>("IsDeleted")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<int?>("MaxUsers")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("TenantId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Tenants");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ClaimType")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ClaimValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<long>("RoleId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("RoleId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetRoleClaims", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ClaimType")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ClaimValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserClaims", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("LoginProvider")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ProviderKey")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ProviderDisplayName")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("LoginProvider", "ProviderKey");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserLogins", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<long>("RoleId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("UserId", "RoleId");
|
|
||||||
|
|
||||||
b.HasIndex("RoleId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserRoles", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<string>("LoginProvider")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Value")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("UserId", "LoginProvider", "Name");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserTokens", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b =>
|
|
||||||
{
|
|
||||||
b.OwnsOne("Fengling.AuthService.Models.TenantInfo", "TenantInfo", b1 =>
|
|
||||||
{
|
|
||||||
b1.Property<long>("ApplicationUserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b1.Property<long>("Id")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("TenantId");
|
|
||||||
|
|
||||||
b1.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("TenantName");
|
|
||||||
|
|
||||||
b1.Property<string>("TenantId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("TenantCode");
|
|
||||||
|
|
||||||
b1.HasKey("ApplicationUserId");
|
|
||||||
|
|
||||||
b1.ToTable("AspNetUsers");
|
|
||||||
|
|
||||||
b1.WithOwner()
|
|
||||||
.HasForeignKey("ApplicationUserId");
|
|
||||||
});
|
|
||||||
|
|
||||||
b.Navigation("TenantInfo")
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationRole", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("RoleId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationRole", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("RoleId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,420 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class InitialCreate : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AccessLogs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
UserName = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
||||||
TenantId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
||||||
Action = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
Resource = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
|
|
||||||
Method = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: true),
|
|
||||||
IpAddress = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
||||||
UserAgent = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
|
|
||||||
Status = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
Duration = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
RequestData = table.Column<string>(type: "text", nullable: true),
|
|
||||||
ResponseData = table.Column<string>(type: "text", nullable: true),
|
|
||||||
ErrorMessage = table.Column<string>(type: "text", nullable: true),
|
|
||||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AccessLogs", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetRoles",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Description = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
|
|
||||||
CreatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
TenantId = table.Column<long>(type: "bigint", nullable: true),
|
|
||||||
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
DisplayName = table.Column<string>(type: "text", nullable: true),
|
|
||||||
Permissions = table.Column<List<string>>(type: "text[]", nullable: true),
|
|
||||||
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetUsers",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
RealName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
|
||||||
Phone = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true),
|
|
||||||
TenantId = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
TenantCode = table.Column<string>(type: "text", nullable: false),
|
|
||||||
TenantName = table.Column<string>(type: "text", nullable: false),
|
|
||||||
CreatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
UpdatedTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
|
||||||
IsDeleted = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
|
||||||
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
PasswordHash = table.Column<string>(type: "text", nullable: true),
|
|
||||||
SecurityStamp = table.Column<string>(type: "text", nullable: true),
|
|
||||||
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
|
|
||||||
PhoneNumber = table.Column<string>(type: "text", nullable: true),
|
|
||||||
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
|
||||||
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AuditLogs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Operator = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
|
||||||
TenantId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
||||||
Operation = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
Action = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
TargetType = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
||||||
TargetId = table.Column<long>(type: "bigint", nullable: true),
|
|
||||||
TargetName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
|
||||||
IpAddress = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
|
||||||
Description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
|
|
||||||
OldValue = table.Column<string>(type: "text", nullable: true),
|
|
||||||
NewValue = table.Column<string>(type: "text", nullable: true),
|
|
||||||
ErrorMessage = table.Column<string>(type: "text", nullable: true),
|
|
||||||
Status = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AuditLogs", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "OAuthApplications",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
ClientId = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
||||||
ClientSecret = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
|
|
||||||
DisplayName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
||||||
RedirectUris = table.Column<string[]>(type: "text[]", nullable: false),
|
|
||||||
PostLogoutRedirectUris = table.Column<string[]>(type: "text[]", nullable: false),
|
|
||||||
Scopes = table.Column<string[]>(type: "text[]", nullable: false),
|
|
||||||
GrantTypes = table.Column<string[]>(type: "text[]", nullable: false),
|
|
||||||
ClientType = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
ConsentType = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
Status = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
Description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
|
|
||||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_OAuthApplications", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Tenants",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
TenantId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
|
||||||
Name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
||||||
ContactName = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
|
||||||
ContactEmail = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
||||||
ContactPhone = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true),
|
|
||||||
MaxUsers = table.Column<int>(type: "integer", nullable: true),
|
|
||||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
Description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
|
|
||||||
Status = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
|
||||||
ExpiresAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
|
||||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
|
||||||
IsDeleted = table.Column<bool>(type: "boolean", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Tenants", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetRoleClaims",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
RoleId = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
ClaimType = table.Column<string>(type: "text", nullable: true),
|
|
||||||
ClaimValue = table.Column<string>(type: "text", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
|
||||||
column: x => x.RoleId,
|
|
||||||
principalTable: "AspNetRoles",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetUserClaims",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
UserId = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
ClaimType = table.Column<string>(type: "text", nullable: true),
|
|
||||||
ClaimValue = table.Column<string>(type: "text", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "AspNetUsers",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetUserLogins",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
LoginProvider = table.Column<string>(type: "text", nullable: false),
|
|
||||||
ProviderKey = table.Column<string>(type: "text", nullable: false),
|
|
||||||
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
|
|
||||||
UserId = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "AspNetUsers",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetUserRoles",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
UserId = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
RoleId = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
|
||||||
column: x => x.RoleId,
|
|
||||||
principalTable: "AspNetRoles",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "AspNetUsers",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "AspNetUserTokens",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
UserId = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
LoginProvider = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Name = table.Column<string>(type: "text", nullable: false),
|
|
||||||
Value = table.Column<string>(type: "text", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "AspNetUsers",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AccessLogs_Action",
|
|
||||||
table: "AccessLogs",
|
|
||||||
column: "Action");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AccessLogs_CreatedAt",
|
|
||||||
table: "AccessLogs",
|
|
||||||
column: "CreatedAt");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AccessLogs_Status",
|
|
||||||
table: "AccessLogs",
|
|
||||||
column: "Status");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AccessLogs_TenantId",
|
|
||||||
table: "AccessLogs",
|
|
||||||
column: "TenantId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AccessLogs_UserName",
|
|
||||||
table: "AccessLogs",
|
|
||||||
column: "UserName");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AspNetRoleClaims_RoleId",
|
|
||||||
table: "AspNetRoleClaims",
|
|
||||||
column: "RoleId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "RoleNameIndex",
|
|
||||||
table: "AspNetRoles",
|
|
||||||
column: "NormalizedName",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AspNetUserClaims_UserId",
|
|
||||||
table: "AspNetUserClaims",
|
|
||||||
column: "UserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AspNetUserLogins_UserId",
|
|
||||||
table: "AspNetUserLogins",
|
|
||||||
column: "UserId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AspNetUserRoles_RoleId",
|
|
||||||
table: "AspNetUserRoles",
|
|
||||||
column: "RoleId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "EmailIndex",
|
|
||||||
table: "AspNetUsers",
|
|
||||||
column: "NormalizedEmail");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AspNetUsers_Phone",
|
|
||||||
table: "AspNetUsers",
|
|
||||||
column: "Phone",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "UserNameIndex",
|
|
||||||
table: "AspNetUsers",
|
|
||||||
column: "NormalizedUserName",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AuditLogs_Action",
|
|
||||||
table: "AuditLogs",
|
|
||||||
column: "Action");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AuditLogs_CreatedAt",
|
|
||||||
table: "AuditLogs",
|
|
||||||
column: "CreatedAt");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AuditLogs_Operation",
|
|
||||||
table: "AuditLogs",
|
|
||||||
column: "Operation");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AuditLogs_Operator",
|
|
||||||
table: "AuditLogs",
|
|
||||||
column: "Operator");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_AuditLogs_TenantId",
|
|
||||||
table: "AuditLogs",
|
|
||||||
column: "TenantId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_OAuthApplications_ClientId",
|
|
||||||
table: "OAuthApplications",
|
|
||||||
column: "ClientId",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Tenants_TenantId",
|
|
||||||
table: "Tenants",
|
|
||||||
column: "TenantId",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AccessLogs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetRoleClaims");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetUserClaims");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetUserLogins");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetUserRoles");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetUserTokens");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AuditLogs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "OAuthApplications");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Tenants");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetRoles");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "AspNetUsers");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,636 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Fengling.AuthService.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(ApplicationDbContext))]
|
|
||||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
|
||||||
{
|
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "10.0.2")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.AccessLog", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Action")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<int>("Duration")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("ErrorMessage")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("Method")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)");
|
|
||||||
|
|
||||||
b.Property<string>("RequestData")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Resource")
|
|
||||||
.HasMaxLength(200)
|
|
||||||
.HasColumnType("character varying(200)");
|
|
||||||
|
|
||||||
b.Property<string>("ResponseData")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("TenantId")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("UserAgent")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("Action");
|
|
||||||
|
|
||||||
b.HasIndex("CreatedAt");
|
|
||||||
|
|
||||||
b.HasIndex("Status");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
|
||||||
|
|
||||||
b.HasIndex("UserName");
|
|
||||||
|
|
||||||
b.ToTable("AccessLogs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.ApplicationRole", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedTime")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(200)
|
|
||||||
.HasColumnType("character varying(200)");
|
|
||||||
|
|
||||||
b.Property<string>("DisplayName")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<bool>("IsSystem")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<List<string>>("Permissions")
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.Property<long?>("TenantId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedName")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("RoleNameIndex");
|
|
||||||
|
|
||||||
b.ToTable("AspNetRoles", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<int>("AccessFailedCount")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedTime")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Email")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<bool>("IsDeleted")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<bool>("LockoutEnabled")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedUserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.Property<string>("PasswordHash")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Phone")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("PhoneNumber")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<bool>("PhoneNumberConfirmed")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<string>("RealName")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("SecurityStamp")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<bool>("TwoFactorEnabled")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedTime")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("character varying(256)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedEmail")
|
|
||||||
.HasDatabaseName("EmailIndex");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedUserName")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("UserNameIndex");
|
|
||||||
|
|
||||||
b.HasIndex("Phone")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("AspNetUsers", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.AuditLog", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("Action")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("ErrorMessage")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("IpAddress")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("NewValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("OldValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Operation")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("Operator")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<long?>("TargetId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<string>("TargetName")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("TargetType")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("TenantId")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("Action");
|
|
||||||
|
|
||||||
b.HasIndex("CreatedAt");
|
|
||||||
|
|
||||||
b.HasIndex("Operation");
|
|
||||||
|
|
||||||
b.HasIndex("Operator");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
|
||||||
|
|
||||||
b.ToTable("AuditLogs");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.OAuthApplication", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ClientId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("ClientSecret")
|
|
||||||
.HasMaxLength(200)
|
|
||||||
.HasColumnType("character varying(200)");
|
|
||||||
|
|
||||||
b.Property<string>("ClientType")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("ConsentType")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<string>("DisplayName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("GrantTypes")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("PostLogoutRedirectUris")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("RedirectUris")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.PrimitiveCollection<string[]>("Scopes")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text[]");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ClientId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("OAuthApplications");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.Tenant", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ContactEmail")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("ContactName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<string>("ContactPhone")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<string>("Description")
|
|
||||||
.HasMaxLength(500)
|
|
||||||
.HasColumnType("character varying(500)");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("ExpiresAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<bool>("IsDeleted")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<int?>("MaxUsers")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)");
|
|
||||||
|
|
||||||
b.Property<string>("Status")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)");
|
|
||||||
|
|
||||||
b.Property<string>("TenantId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("TenantId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Tenants");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ClaimType")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ClaimValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<long>("RoleId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("RoleId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetRoleClaims", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
|
||||||
|
|
||||||
b.Property<string>("ClaimType")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ClaimValue")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserClaims", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("LoginProvider")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ProviderKey")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("ProviderDisplayName")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("LoginProvider", "ProviderKey");
|
|
||||||
|
|
||||||
b.HasIndex("UserId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserLogins", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<long>("RoleId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.HasKey("UserId", "RoleId");
|
|
||||||
|
|
||||||
b.HasIndex("RoleId");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserRoles", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("UserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<string>("LoginProvider")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("Value")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("UserId", "LoginProvider", "Name");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUserTokens", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b =>
|
|
||||||
{
|
|
||||||
b.OwnsOne("Fengling.AuthService.Models.TenantInfo", "TenantInfo", b1 =>
|
|
||||||
{
|
|
||||||
b1.Property<long>("ApplicationUserId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b1.Property<long>("Id")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("TenantId");
|
|
||||||
|
|
||||||
b1.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("TenantName");
|
|
||||||
|
|
||||||
b1.Property<string>("TenantId")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("TenantCode");
|
|
||||||
|
|
||||||
b1.HasKey("ApplicationUserId");
|
|
||||||
|
|
||||||
b1.ToTable("AspNetUsers");
|
|
||||||
|
|
||||||
b1.WithOwner()
|
|
||||||
.HasForeignKey("ApplicationUserId");
|
|
||||||
});
|
|
||||||
|
|
||||||
b.Navigation("TenantInfo")
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationRole", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("RoleId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationRole", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("RoleId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Fengling.AuthService.Models.ApplicationUser", null)
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public class AccessLog
|
|
||||||
{
|
|
||||||
[Key]
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
public string? UserName { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
public string? TenantId { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string Action { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(200)]
|
|
||||||
public string? Resource { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(10)]
|
|
||||||
public string? Method { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
public string? IpAddress { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(500)]
|
|
||||||
public string? UserAgent { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string Status { get; set; } = "success";
|
|
||||||
|
|
||||||
public int Duration { get; set; }
|
|
||||||
|
|
||||||
public string? RequestData { get; set; }
|
|
||||||
|
|
||||||
public string? ResponseData { get; set; }
|
|
||||||
|
|
||||||
public string? ErrorMessage { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public class ApplicationRole : IdentityRole<long>
|
|
||||||
{
|
|
||||||
public string? Description { get; set; }
|
|
||||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
|
||||||
public long? TenantId { get; set; }
|
|
||||||
public bool IsSystem { get; set; }
|
|
||||||
public string? DisplayName { get; set; }
|
|
||||||
public List<string>? Permissions { get; set; }
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public class ApplicationUser : IdentityUser<long>
|
|
||||||
{
|
|
||||||
public string? RealName { get; set; }
|
|
||||||
public string? Phone { get; set; }
|
|
||||||
public TenantInfo TenantInfo { get; set; } = null!;
|
|
||||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
|
||||||
public DateTime? UpdatedTime { get; set; }
|
|
||||||
public bool IsDeleted { get; set; }
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public class AuditLog
|
|
||||||
{
|
|
||||||
[Key]
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
[Required]
|
|
||||||
public string Operator { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
public string? TenantId { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string Operation { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string Action { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
public string? TargetType { get; set; }
|
|
||||||
|
|
||||||
public long? TargetId { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(100)]
|
|
||||||
public string? TargetName { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
public string IpAddress { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(500)]
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public string? OldValue { get; set; }
|
|
||||||
|
|
||||||
public string? NewValue { get; set; }
|
|
||||||
|
|
||||||
public string? ErrorMessage { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string Status { get; set; } = "success";
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public class OAuthApplication
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
public string ClientId { get; set; } = string.Empty;
|
|
||||||
public string? ClientSecret { get; set; }
|
|
||||||
public string DisplayName { get; set; } = string.Empty;
|
|
||||||
public string[] RedirectUris { get; set; } = Array.Empty<string>();
|
|
||||||
public string[] PostLogoutRedirectUris { get; set; } = Array.Empty<string>();
|
|
||||||
public string[] Scopes { get; set; } = Array.Empty<string>();
|
|
||||||
public string[] GrantTypes { get; set; } = Array.Empty<string>();
|
|
||||||
public string ClientType { get; set; } = "public";
|
|
||||||
public string ConsentType { get; set; } = "implicit";
|
|
||||||
public string Status { get; set; } = "active";
|
|
||||||
public string? Description { get; set; }
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
public DateTime? UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public class Tenant
|
|
||||||
{
|
|
||||||
private long _id;
|
|
||||||
private string _tenantId;
|
|
||||||
private string _name;
|
|
||||||
|
|
||||||
[Key]
|
|
||||||
public long Id
|
|
||||||
{
|
|
||||||
get => _id;
|
|
||||||
set => _id = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
[Required]
|
|
||||||
public string TenantId
|
|
||||||
{
|
|
||||||
get => _tenantId;
|
|
||||||
set => _tenantId = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MaxLength(100)]
|
|
||||||
[Required]
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get => _name;
|
|
||||||
set => _name = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MaxLength(50)]
|
|
||||||
[Required]
|
|
||||||
public string ContactName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(100)]
|
|
||||||
[Required]
|
|
||||||
[EmailAddress]
|
|
||||||
public string ContactEmail { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string? ContactPhone { get; set; }
|
|
||||||
|
|
||||||
public int? MaxUsers { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
||||||
|
|
||||||
[MaxLength(500)]
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
[MaxLength(20)]
|
|
||||||
public string Status { get; set; } = "active";
|
|
||||||
|
|
||||||
public DateTime? ExpiresAt { get; set; }
|
|
||||||
|
|
||||||
public DateTime? UpdatedAt { get; set; }
|
|
||||||
|
|
||||||
public bool IsDeleted { get; set; }
|
|
||||||
|
|
||||||
public TenantInfo Info => new(Id, TenantId, Name);
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
namespace Fengling.AuthService.Models;
|
|
||||||
|
|
||||||
public record TenantInfo(long Id, string TenantId, string Name);
|
|
||||||
39
Program.cs
39
Program.cs
@ -1,11 +1,13 @@
|
|||||||
|
using System.Reflection;
|
||||||
using Fengling.AuthService.Configuration;
|
using Fengling.AuthService.Configuration;
|
||||||
using Fengling.AuthService.Data;
|
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||||
using Fengling.AuthService.Models;
|
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||||
|
using Fengling.Platform.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.OpenApi;
|
using Microsoft.OpenApi;
|
||||||
using OpenTelemetry;
|
using NetCorePal.Extensions.DependencyInjection;
|
||||||
using OpenTelemetry.Resources;
|
using OpenTelemetry.Resources;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
@ -21,23 +23,17 @@ Log.Logger = new LoggerConfiguration()
|
|||||||
builder.Host.UseSerilog();
|
builder.Host.UseSerilog();
|
||||||
|
|
||||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
builder.Services.AddDbContext<PlatformDbContext>(options =>
|
||||||
{
|
{
|
||||||
if (connectionString.StartsWith("DataSource="))
|
|
||||||
{
|
|
||||||
options.UseInMemoryDatabase(connectionString);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
options.UseNpgsql(connectionString);
|
options.UseNpgsql(connectionString);
|
||||||
}
|
options.UseOpenIddict();
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
|
|
||||||
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
|
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
|
||||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
.AddEntityFrameworkStores<PlatformDbContext>()
|
||||||
.AddDefaultTokenProviders();
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
builder.Services.AddAuthentication(options =>
|
builder.Services.AddAuthentication(options =>
|
||||||
@ -67,6 +63,15 @@ builder.Services.AddControllersWithViews();
|
|||||||
builder.Services.AddHealthChecks()
|
builder.Services.AddHealthChecks()
|
||||||
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection")!);
|
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection")!);
|
||||||
|
|
||||||
|
|
||||||
|
builder.Services.AddRepositories(typeof(PlatformDbContext).Assembly);
|
||||||
|
builder.Services.AddMediatR(x => x.RegisterServicesFromAssemblies(
|
||||||
|
typeof(PlatformDbContext).Assembly,
|
||||||
|
Assembly.GetExecutingAssembly())
|
||||||
|
.AddCommandLockBehavior()
|
||||||
|
.AddKnownExceptionValidationBehavior()
|
||||||
|
.AddUnitOfWorkBehaviors()
|
||||||
|
);
|
||||||
builder.Services.AddSwaggerGen(options =>
|
builder.Services.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
options.SwaggerDoc("v1", new OpenApiInfo
|
options.SwaggerDoc("v1", new OpenApiInfo
|
||||||
@ -93,9 +98,17 @@ var app = builder.Build();
|
|||||||
|
|
||||||
using (var scope = app.Services.CreateScope())
|
using (var scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
await SeedData.Initialize(scope.ServiceProvider);
|
await scope.InitializeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.UseCors(x =>
|
||||||
|
{
|
||||||
|
x.SetIsOriginAllowed(origin => true)
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowCredentials()
|
||||||
|
.Build();
|
||||||
|
});
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
|
|||||||
@ -4,23 +4,27 @@ namespace Fengling.AuthService.ViewModels;
|
|||||||
|
|
||||||
public class RegisterViewModel
|
public class RegisterViewModel
|
||||||
{
|
{
|
||||||
|
[Required(ErrorMessage = "租户编号不能为空")]
|
||||||
|
[StringLength(10,MinimumLength = 4,ErrorMessage = "租户编号长度必须在4·10个字符之间")]
|
||||||
|
public string TenantCode { get; set; }
|
||||||
|
|
||||||
[Required(ErrorMessage = "用户名不能为空")]
|
[Required(ErrorMessage = "用户名不能为空")]
|
||||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "用户名长度必须在3-50个字符之间")]
|
[StringLength(50, MinimumLength = 3, ErrorMessage = "用户名长度必须在3-50个字符之间")]
|
||||||
public string Username { get; set; }
|
public string Username { get; set; } = default!;
|
||||||
|
|
||||||
[Required(ErrorMessage = "邮箱不能为空")]
|
[Required(ErrorMessage = "邮箱不能为空")]
|
||||||
[EmailAddress(ErrorMessage = "请输入有效的邮箱地址")]
|
[EmailAddress(ErrorMessage = "请输入有效的邮箱地址")]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }= default!;
|
||||||
|
|
||||||
[Required(ErrorMessage = "密码不能为空")]
|
[Required(ErrorMessage = "密码不能为空")]
|
||||||
[StringLength(100, MinimumLength = 6, ErrorMessage = "密码长度必须在6-100个字符之间")]
|
[StringLength(100, MinimumLength = 6, ErrorMessage = "密码长度必须在6-100个字符之间")]
|
||||||
[DataType(DataType.Password)]
|
[DataType(DataType.Password)]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }= default!;
|
||||||
|
|
||||||
[Required(ErrorMessage = "确认密码不能为空")]
|
[Required(ErrorMessage = "确认密码不能为空")]
|
||||||
[DataType(DataType.Password)]
|
[DataType(DataType.Password)]
|
||||||
[Compare("Password", ErrorMessage = "两次输入的密码不一致")]
|
[Compare("Password", ErrorMessage = "两次输入的密码不一致")]
|
||||||
public string ConfirmPassword { get; set; }
|
public string ConfirmPassword { get; set; }= default!;
|
||||||
|
|
||||||
public string ReturnUrl { get; set; }
|
public string ReturnUrl { get; set; }= default!;
|
||||||
}
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
@using Microsoft.Extensions.Primitives
|
||||||
@model Fengling.AuthService.ViewModels.AuthorizeViewModel
|
@model Fengling.AuthService.ViewModels.AuthorizeViewModel
|
||||||
|
|
||||||
@{
|
@{
|
||||||
@ -10,7 +11,8 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="text-center mb-8">
|
<div class="text-center mb-8">
|
||||||
<div class="inline-flex h-16 w-16 items-center justify-center rounded-full bg-primary/10 mb-4">
|
<div class="inline-flex h-16 w-16 items-center justify-center rounded-full bg-primary/10 mb-4">
|
||||||
<svg class="h-8 w-8 text-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="h-8 w-8 text-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@ -27,7 +29,8 @@
|
|||||||
<div class="p-6 border-b border-border">
|
<div class="p-6 border-b border-border">
|
||||||
<div class="flex items-start gap-4">
|
<div class="flex items-start gap-4">
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<div class="h-12 w-12 rounded-lg bg-primary flex items-center justify-center text-primary-foreground text-lg font-semibold">
|
<div
|
||||||
|
class="h-12 w-12 rounded-lg bg-primary flex items-center justify-center text-primary-foreground text-lg font-semibold">
|
||||||
@(Model.ApplicationName?.Substring(0, Math.Min(1, Model.ApplicationName.Length)).ToUpper() ?? "A")
|
@(Model.ApplicationName?.Substring(0, Math.Min(1, Model.ApplicationName.Length)).ToUpper() ?? "A")
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -49,7 +52,10 @@
|
|||||||
@foreach (var scope in Model.Scopes)
|
@foreach (var scope in Model.Scopes)
|
||||||
{
|
{
|
||||||
<div class="flex items-start gap-3 p-3 rounded-lg bg-muted/50">
|
<div class="flex items-start gap-3 p-3 rounded-lg bg-muted/50">
|
||||||
<svg class="h-5 w-5 text-primary mt-0.5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="h-5 w-5 text-primary mt-0.5 flex-shrink-0"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
||||||
<polyline points="22 4 12 14.01 9 11.01"/>
|
<polyline points="22 4 12 14.01 9 11.01"/>
|
||||||
</svg>
|
</svg>
|
||||||
@ -70,7 +76,9 @@
|
|||||||
<!-- Warning Section -->
|
<!-- Warning Section -->
|
||||||
<div class="p-4 bg-destructive/5 border-t border-border">
|
<div class="p-4 bg-destructive/5 border-t border-border">
|
||||||
<div class="flex items-start gap-2">
|
<div class="flex items-start gap-2">
|
||||||
<svg class="h-4 w-4 text-destructive mt-0.5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="h-4 w-4 text-destructive mt-0.5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/>
|
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/>
|
||||||
<path d="M12 9v4"/>
|
<path d="M12 9v4"/>
|
||||||
<path d="M12 17h.01"/>
|
<path d="M12 17h.01"/>
|
||||||
@ -83,19 +91,28 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<form method="post" class="mt-6 space-y-3">
|
<form asp-controller="Authorization" asp-action="Authorize" method="post" class="mt-6 space-y-3">
|
||||||
|
@* Flow the request parameters so they can be received by the Accept/Reject actions: *@
|
||||||
|
@foreach (var parameter in Context.Request.HasFormContentType ?
|
||||||
|
(IEnumerable<KeyValuePair<string, StringValues>>) Context.Request.Form : Context.Request.Query)
|
||||||
|
{
|
||||||
|
<input type="hidden" name="@parameter.Key" value="@parameter.Value" />
|
||||||
|
}
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-3">
|
<div class="grid grid-cols-2 gap-3">
|
||||||
<button type="submit" name="action" value="accept"
|
<button type="submit" name="submit.Accept" value="Yes"
|
||||||
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 bg-primary text-primary-foreground hover:bg-primary/90 h-11 px-8 shadow">
|
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 bg-primary text-primary-foreground hover:bg-primary/90 h-11 px-8 shadow">
|
||||||
<svg class="mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
||||||
<polyline points="22 4 12 14.01 9 11.01"/>
|
<polyline points="22 4 12 14.01 9 11.01"/>
|
||||||
</svg>
|
</svg>
|
||||||
授权
|
授权
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" name="action" value="deny"
|
<button type="submit" name="submit.Deny" value="No"
|
||||||
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-11 px-8">
|
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-11 px-8">
|
||||||
<svg class="mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||||
|
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||||
</svg>
|
</svg>
|
||||||
@ -114,6 +131,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@functions {
|
@functions {
|
||||||
|
|
||||||
private string GetScopeDisplayName(string scope)
|
private string GetScopeDisplayName(string scope)
|
||||||
{
|
{
|
||||||
return scope switch
|
return scope switch
|
||||||
@ -143,4 +161,5 @@
|
|||||||
_ => "自定义权限范围"
|
_ => "自定义权限范围"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "DataSource=:memory:"
|
"DefaultConnection": "Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542"
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Host=192.168.100.10;Port=5432;Database=fengling_auth;Username=movingsam;Password=sl52788542"
|
"DefaultConnection": "Host=81.68.223.70;Port=15432;Database=fengling_auth;Username=movingsam;Password=sl52788542"
|
||||||
},
|
},
|
||||||
"Jwt": {
|
"Jwt": {
|
||||||
"Issuer": "https://auth.fengling.local",
|
"Issuer": "http://localhost:5132",
|
||||||
"Audience": "fengling-api",
|
"Audience": "fengling-api",
|
||||||
"Secret": "FenglingAuthSecretKey2024!ChangeThisInProduction!"
|
"Secret": "FenglingAuthSecretKey2024!ChangeThisInProduction!"
|
||||||
},
|
},
|
||||||
"OpenIddict": {
|
"OpenIddict": {
|
||||||
"Issuer": "https://auth.fengling.local",
|
"Issuer": "http://localhost:5132",
|
||||||
"Audience": "fengling-api"
|
"Audience": "fengling-api"
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
|
|||||||
BIN
bin\Debug/net10.0/BuildHost-net472/Microsoft.Build.Locator.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/Microsoft.Build.Locator.dll
Executable file
Binary file not shown.
Binary file not shown.
@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.Build" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.Build.Utilities.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.Build.Tasks.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.IO.Redist" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.1.0.0" newVersion="6.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.4.0" newVersion="4.0.4.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.1.0" newVersion="6.0.1.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
||||||
BIN
bin\Debug/net10.0/BuildHost-net472/Microsoft.IO.Redist.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/Microsoft.IO.Redist.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/Newtonsoft.Json.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/Newtonsoft.Json.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.Buffers.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.Buffers.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.Collections.Immutable.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.Collections.Immutable.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.CommandLine.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.CommandLine.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.Memory.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.Memory.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.Numerics.Vectors.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.Numerics.Vectors.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.Runtime.CompilerServices.Unsafe.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.Runtime.CompilerServices.Unsafe.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/System.Threading.Tasks.Extensions.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/System.Threading.Tasks.Extensions.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/cs/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/cs/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/de/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/de/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/es/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/es/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/fr/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/fr/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/it/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/it/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/ja/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/ja/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/ko/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/ko/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/pl/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/pl/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/pt-BR/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/pt-BR/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/ru/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/ru/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/tr/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/tr/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/zh-Hans/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/zh-Hans/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-net472/zh-Hant/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-net472/zh-Hant/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/Microsoft.Build.Locator.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/Microsoft.Build.Locator.dll
Executable file
Binary file not shown.
@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v8.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v8.0": {
|
||||||
|
"Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost/5.0.0-2.25567.12": {
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Build.Locator": "1.10.2",
|
||||||
|
"Newtonsoft.Json": "13.0.3",
|
||||||
|
"System.Collections.Immutable": "9.0.0",
|
||||||
|
"System.CommandLine": "2.0.0-rtm.25509.106"
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.dll": {}
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"cs/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "cs"
|
||||||
|
},
|
||||||
|
"de/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "de"
|
||||||
|
},
|
||||||
|
"es/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "es"
|
||||||
|
},
|
||||||
|
"fr/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "fr"
|
||||||
|
},
|
||||||
|
"it/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "it"
|
||||||
|
},
|
||||||
|
"ja/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "ja"
|
||||||
|
},
|
||||||
|
"ko/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "ko"
|
||||||
|
},
|
||||||
|
"pl/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "pl"
|
||||||
|
},
|
||||||
|
"pt-BR/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "pt-BR"
|
||||||
|
},
|
||||||
|
"ru/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "ru"
|
||||||
|
},
|
||||||
|
"tr/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "tr"
|
||||||
|
},
|
||||||
|
"zh-Hans/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "zh-Hans"
|
||||||
|
},
|
||||||
|
"zh-Hant/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll": {
|
||||||
|
"locale": "zh-Hant"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Build.Locator/1.10.2": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net8.0/Microsoft.Build.Locator.dll": {
|
||||||
|
"assemblyVersion": "1.0.0.0",
|
||||||
|
"fileVersion": "1.10.2.26959"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.3": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net6.0/Newtonsoft.Json.dll": {
|
||||||
|
"assemblyVersion": "13.0.0.0",
|
||||||
|
"fileVersion": "13.0.3.27908"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/9.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net8.0/System.Collections.Immutable.dll": {
|
||||||
|
"assemblyVersion": "9.0.0.0",
|
||||||
|
"fileVersion": "9.0.24.52809"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.CommandLine/2.0.0-rtm.25509.106": {
|
||||||
|
"runtime": {
|
||||||
|
"lib/net8.0/System.CommandLine.dll": {
|
||||||
|
"assemblyVersion": "2.0.0.0",
|
||||||
|
"fileVersion": "2.0.25.51006"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"lib/net8.0/cs/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "cs"
|
||||||
|
},
|
||||||
|
"lib/net8.0/de/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "de"
|
||||||
|
},
|
||||||
|
"lib/net8.0/es/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "es"
|
||||||
|
},
|
||||||
|
"lib/net8.0/fr/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "fr"
|
||||||
|
},
|
||||||
|
"lib/net8.0/it/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "it"
|
||||||
|
},
|
||||||
|
"lib/net8.0/ja/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "ja"
|
||||||
|
},
|
||||||
|
"lib/net8.0/ko/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "ko"
|
||||||
|
},
|
||||||
|
"lib/net8.0/pl/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "pl"
|
||||||
|
},
|
||||||
|
"lib/net8.0/pt-BR/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "pt-BR"
|
||||||
|
},
|
||||||
|
"lib/net8.0/ru/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "ru"
|
||||||
|
},
|
||||||
|
"lib/net8.0/tr/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "tr"
|
||||||
|
},
|
||||||
|
"lib/net8.0/zh-Hans/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "zh-Hans"
|
||||||
|
},
|
||||||
|
"lib/net8.0/zh-Hant/System.CommandLine.resources.dll": {
|
||||||
|
"locale": "zh-Hant"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost/5.0.0-2.25567.12": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
},
|
||||||
|
"Microsoft.Build.Locator/1.10.2": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-F+nLS7IpgtslyxNvtD6Jalnf5WU08lu8yfJBNQl3cbEF3AMUphs4t7nPuRYaaU8QZyGrqtVi7i73LhAe/yHx7A==",
|
||||||
|
"path": "microsoft.build.locator/1.10.2",
|
||||||
|
"hashPath": "microsoft.build.locator.1.10.2.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json/13.0.3": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==",
|
||||||
|
"path": "newtonsoft.json/13.0.3",
|
||||||
|
"hashPath": "newtonsoft.json.13.0.3.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable/9.0.0": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-QhkXUl2gNrQtvPmtBTQHb0YsUrDiDQ2QS09YbtTTiSjGcf7NBqtYbrG/BE06zcBPCKEwQGzIv13IVdXNOSub2w==",
|
||||||
|
"path": "system.collections.immutable/9.0.0",
|
||||||
|
"hashPath": "system.collections.immutable.9.0.0.nupkg.sha512"
|
||||||
|
},
|
||||||
|
"System.CommandLine/2.0.0-rtm.25509.106": {
|
||||||
|
"type": "package",
|
||||||
|
"serviceable": true,
|
||||||
|
"sha512": "sha512-IdCQOFNHQfK0hu3tzWOHFJLMaiEOR/4OynmOh+IfukrTIsCR4TTDm7lpuXQyMZ0eRfIyUcz06gHGJNlILAq/6A==",
|
||||||
|
"path": "system.commandline/2.0.0-rtm.25509.106",
|
||||||
|
"hashPath": "system.commandline.2.0.0-rtm.25509.106.nupkg.sha512"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"tfm": "net8.0",
|
||||||
|
"framework": {
|
||||||
|
"name": "Microsoft.NETCore.App",
|
||||||
|
"version": "8.0.0"
|
||||||
|
},
|
||||||
|
"rollForward": "Major",
|
||||||
|
"configProperties": {
|
||||||
|
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
|
||||||
|
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
bin\Debug/net10.0/BuildHost-netcore/Newtonsoft.Json.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/Newtonsoft.Json.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/System.Collections.Immutable.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/System.Collections.Immutable.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/System.CommandLine.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/System.CommandLine.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/cs/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/cs/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/de/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/de/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/es/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/es/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/fr/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/fr/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/it/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/it/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/ja/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/ja/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/ko/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/ko/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/pl/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/pl/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/pt-BR/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/pt-BR/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/ru/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/ru/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/tr/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/tr/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/zh-Hans/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/zh-Hans/System.CommandLine.resources.dll
Executable file
Binary file not shown.
BIN
bin\Debug/net10.0/BuildHost-netcore/zh-Hant/System.CommandLine.resources.dll
Executable file
BIN
bin\Debug/net10.0/BuildHost-netcore/zh-Hant/System.CommandLine.resources.dll
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user