@(editingApplication != null ? "Chỉnh sửa Application" : "Tạo Application Mới")
Thông tin cơ bản
Public Confidential Explicit Implicit
@if (applicationForm.ClientType == ClientTypes.Confidential)
{
}
Cấu hình Endpoints
Redirect URIs { if (e.Key == "Enter") { AddRedirectUri(); } })" />
@foreach (var uri in applicationForm.RedirectUris)
{
}
Post Logout URIs { if (e.Key == "Enter") { AddPostLogoutUri(); } })" />
@foreach (var uri in applicationForm.PostLogoutRedirectUris)
{
}
Permissions & Requirements
@foreach (var permission in permissionChecks)
{
@permission.Key.Split('.').Last()
}
@foreach (var selectedPermission in GetSelectedPermissions())
{
}
@if (applicationForm.ClientType == ClientTypes.Public)
{
Requirements
@foreach (var requirement in requirementChecks)
{
}
}
Hủy
@(editingApplication != null ? "Cập nhật" : "Tạo mới")
Chi tiết Application
@if (selectedApplication != null)
{
Thông tin cơ bản
ID: @selectedApplication.Id
Client ID: @selectedApplication.ClientId
Display Name: @selectedApplication.DisplayName
Type: @selectedApplication.ClientType
Consent: @selectedApplication.ConsentType
🔒 Bảo mật
Client Secret:
@if (!string.IsNullOrEmpty(selectedApplication.ClientSecret))
{
Có
}
else
{
Không
}
@if (selectedApplication.RedirectUris.Any())
{
🔗 Redirect URIs
@foreach (var uri in selectedApplication.RedirectUris)
{
}
}
@if (selectedApplication.Permissions.Any())
{
🛡️ Permissions
@foreach (var permission in selectedApplication.Permissions)
{
}
}
@if (selectedApplication.Requirements.Any())
{
⚙️ Requirements
@if (selectedApplication.Requirements.Any())
{
@foreach (var requirement in selectedApplication.Requirements)
{
}
}
else
{
Không có requirements nào được thiết lập
}
}
}
Đóng
@code {
private List filteredApplications = new();
private bool loadingApplications = false;
private bool ShowApplicationDialog = false;
private bool ShowDetailsDialog = false;
private bool showClientSecret = false;
private ApplicationInfo? editingApplication = null;
private ApplicationInfo? selectedApplication = null;
private ApplicationForm applicationForm = new();
private string redirectUriInput = string.Empty;
private string postLogoutUriInput = string.Empty;
private string customScopeInput = string.Empty;
private HashSet customScopes = new();
private Dictionary permissionChecks = new();
private Dictionary requirementChecks = new();
private List availableScopes = new();
public class ApplicationInfo
{
public string Id { get; set; } = string.Empty;
public string ApplicationType { get; set; } = string.Empty;
public string ClientId { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string ClientType { get; set; } = string.Empty;
public string ConsentType { get; set; } = string.Empty;
public List RedirectUris { get; set; } = new();
public List PostLogoutRedirectUris { get; set; } = new();
public List Permissions { get; set; } = new();
public List Requirements { get; set; } = new();
public string? ClientSecret { get; set; }
}
public class ApplicationForm
{
public string ClientId { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string ClientType { get; set; } = ClientTypes.Public;
public string ConsentType { get; set; } = ConsentTypes.Explicit;
public string? ClientSecret { get; set; }
public List RedirectUris { get; set; } = new();
public List PostLogoutRedirectUris { get; set; } = new();
}
private string applicationSearchTerm = "";
protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity?.IsAuthenticated == true)
{
InitializePermissionChecks();
InitializeRequirementChecks();
await LoadApplicationsAsync();
await LoadAvailableScopesAsync();
}
}
private void InitializePermissionChecks()
{
permissionChecks.Clear();
permissionChecks.Add(Permissions.Endpoints.Authorization, false);
permissionChecks.Add(Permissions.Endpoints.EndSession, false);
permissionChecks.Add(Permissions.Endpoints.Token, false);
permissionChecks.Add(Permissions.Endpoints.Introspection, false);
permissionChecks.Add(Permissions.GrantTypes.AuthorizationCode, false);
permissionChecks.Add(Permissions.GrantTypes.RefreshToken, false);
permissionChecks.Add(Permissions.GrantTypes.ClientCredentials, false);
permissionChecks.Add(Permissions.ResponseTypes.Code, false);
permissionChecks.Add(Permissions.ResponseTypes.Token, false);
permissionChecks.Add(Permissions.Scopes.Email, false);
permissionChecks.Add(Permissions.Scopes.Profile, false);
permissionChecks.Add(Permissions.Scopes.Roles, false);
foreach (var scope in availableScopes)
{
var scopePermission = Permissions.Prefixes.Scope + scope;
if (!permissionChecks.ContainsKey(scopePermission))
{
permissionChecks.Add(scopePermission, false);
}
}
}
private void InitializeRequirementChecks()
{
requirementChecks = new() {
{ Requirements.Features.ProofKeyForCodeExchange, false }
};
}
private void OnClientTypeChanged(string newClientType)
{
applicationForm.ClientType = newClientType;
if (newClientType == ClientTypes.Public)
{
applicationForm.ClientSecret = null;
}
StateHasChanged();
}
private void OnPermissionSelectionChanged(IEnumerable selectedValues)
{
foreach (var key in permissionChecks.Keys.ToList())
{
permissionChecks[key] = false;
}
foreach (var value in selectedValues)
{
if (permissionChecks.ContainsKey(value))
{
permissionChecks[value] = true;
}
}
StateHasChanged();
}
private IEnumerable GetSelectedPermissions()
{
return permissionChecks.Where(x => x.Value).Select(x => x.Key);
}
private void RemovePermission(string permission)
{
if (permissionChecks.ContainsKey(permission))
{
permissionChecks[permission] = false;
StateHasChanged();
}
}
private IEnumerable FilteredApplications =>
string.IsNullOrWhiteSpace(applicationSearchTerm)
? filteredApplications
: filteredApplications.Where(r =>
(r.ClientId != null && r.ClientId.Contains(applicationSearchTerm, StringComparison.OrdinalIgnoreCase)) ||
(r.DisplayName != null && r.DisplayName.Contains(applicationSearchTerm, StringComparison.OrdinalIgnoreCase)) ||
(r.ClientType != null && r.ClientType.Contains(applicationSearchTerm, StringComparison.OrdinalIgnoreCase)) ||
(r.Id != null && r.Id.Contains(applicationSearchTerm, StringComparison.OrdinalIgnoreCase)));
private async Task LoadApplicationsAsync()
{
try
{
loadingApplications = true;
filteredApplications.Clear();
await foreach (var app in ApplicationManager.ListAsync())
{
string? clientSecret = null;
try
{
var properties = await ApplicationManager.GetPropertiesAsync(app);
clientSecret = properties.ContainsKey("client_secret") ? properties["client_secret"].ToString() : null;
if (string.IsNullOrEmpty(clientSecret))
{
var clientType = await ApplicationManager.GetClientTypeAsync(app);
if (clientType == ClientTypes.Confidential)
{
clientSecret = "***";
}
}
}
catch
{
var clientType = await ApplicationManager.GetClientTypeAsync(app);
if (clientType == ClientTypes.Confidential)
{
clientSecret = "***";
}
}
filteredApplications.Add(new ApplicationInfo
{
Id = await ApplicationManager.GetIdAsync(app) ?? string.Empty,
ApplicationType = await ApplicationManager.GetApplicationTypeAsync(app) ?? string.Empty,
ClientId = await ApplicationManager.GetClientIdAsync(app) ?? string.Empty,
DisplayName = await ApplicationManager.GetDisplayNameAsync(app) ?? string.Empty,
ClientType = await ApplicationManager.GetClientTypeAsync(app) ?? string.Empty,
ConsentType = await ApplicationManager.GetConsentTypeAsync(app) ?? string.Empty,
RedirectUris = (await ApplicationManager.GetRedirectUrisAsync(app)).Select(u => u.ToString()).ToList(),
PostLogoutRedirectUris = (await ApplicationManager.GetPostLogoutRedirectUrisAsync(app)).Select(u => u.ToString()).ToList(),
Permissions = (await ApplicationManager.GetPermissionsAsync(app)).ToList(),
Requirements = (await ApplicationManager.GetRequirementsAsync(app)).ToList(),
ClientSecret = clientSecret
});
}
}
catch (Exception ex)
{
Snackbar.Add($"Lỗi khi tải applications: {ex.Message}", Severity.Error);
}
finally
{
loadingApplications = false;
StateHasChanged();
}
}
private async Task LoadAvailableScopesAsync()
{
try
{
availableScopes.Clear();
await foreach (var scope in ScopeManager.ListAsync())
{
var scopeName = await ScopeManager.GetNameAsync(scope);
if (!string.IsNullOrEmpty(scopeName))
{
availableScopes.Add(scopeName);
}
}
}
catch (Exception ex)
{
Snackbar.Add($"Lỗi khi tải scopes: {ex.Message}", Severity.Error);
}
}
private void ViewApplicationDetails(ApplicationInfo application)
{
selectedApplication = application;
showClientSecret = false;
ShowDetailsDialog = true;
}
private void CloseDetailsDialog()
{
ShowDetailsDialog = false;
selectedApplication = null;
showClientSecret = false;
}
private void ToggleClientSecretVisibility()
{
showClientSecret = !showClientSecret;
}
private async void OpenApplicationDialog(ApplicationInfo? application = null)
{
await LoadAvailableScopesAsync();
InitializePermissionChecks();
ShowApplicationDialog = true;
editingApplication = application;
ResetApplicationForm();
if (application != null)
{
applicationForm = new ApplicationForm
{
ClientId = application.ClientId,
DisplayName = application.DisplayName,
ClientType = application.ClientType,
ConsentType = application.ConsentType,
RedirectUris = new(application.RedirectUris),
PostLogoutRedirectUris = new(application.PostLogoutRedirectUris),
ClientSecret = application.ClientType == ClientTypes.Confidential ? string.Empty : null
};
foreach (var permission in application.Permissions)
{
if (permissionChecks.ContainsKey(permission)) permissionChecks[permission] = true;
else if (permission.StartsWith(Permissions.Prefixes.Scope)) customScopes.Add(permission[Permissions.Prefixes.Scope.Length..]);
}
foreach (var requirement in application.Requirements)
{
if (requirementChecks.ContainsKey(requirement)) requirementChecks[requirement] = true;
}
}
StateHasChanged();
}
private void EditApplication(ApplicationInfo application) => OpenApplicationDialog(application);
private void ResetApplicationForm()
{
applicationForm = new();
redirectUriInput = string.Empty;
postLogoutUriInput = string.Empty;
customScopeInput = string.Empty;
customScopes.Clear();
foreach (var key in permissionChecks.Keys.ToList()) permissionChecks[key] = false;
foreach (var key in requirementChecks.Keys.ToList()) requirementChecks[key] = false;
}
private void AddRedirectUri()
{
if (!string.IsNullOrWhiteSpace(redirectUriInput))
{
if (Uri.TryCreate(redirectUriInput.Trim(), UriKind.Absolute, out _))
{
if (!applicationForm.RedirectUris.Contains(redirectUriInput.Trim()))
{
applicationForm.RedirectUris.Add(redirectUriInput.Trim());
redirectUriInput = string.Empty;
StateHasChanged();
}
else
{
Snackbar.Add("URI này đã tồn tại", Severity.Warning);
}
}
else
{
Snackbar.Add("URI không hợp lệ. Vui lòng nhập URI đầy đủ (ví dụ: https://example.com/login-callback)", Severity.Error);
}
}
}
private void RemoveRedirectUri(string uri) => applicationForm.RedirectUris.Remove(uri);
private void AddPostLogoutUri()
{
if (!string.IsNullOrWhiteSpace(postLogoutUriInput))
{
if (Uri.TryCreate(postLogoutUriInput.Trim(), UriKind.Absolute, out _))
{
if (!applicationForm.PostLogoutRedirectUris.Contains(postLogoutUriInput.Trim()))
{
applicationForm.PostLogoutRedirectUris.Add(postLogoutUriInput.Trim());
postLogoutUriInput = string.Empty;
StateHasChanged();
}
else
{
Snackbar.Add("URI này đã tồn tại", Severity.Warning);
}
}
else
{
Snackbar.Add("URI không hợp lệ. Vui lòng nhập URI đầy đủ (ví dụ: https://example.com/logout-callback)", Severity.Error);
}
}
}
private void RemovePostLogoutUri(string uri) => applicationForm.PostLogoutRedirectUris.Remove(uri);
private void AddCustomScope()
{
if (!string.IsNullOrWhiteSpace(customScopeInput) && !customScopes.Contains(customScopeInput))
{
customScopes.Add(customScopeInput);
customScopeInput = string.Empty;
}
}
private void RemoveCustomScope(string scope) => customScopes.Remove(scope);
private async Task SaveApplication()
{
try
{
if (string.IsNullOrWhiteSpace(applicationForm.ClientId))
{
Snackbar.Add("Client ID là bắt buộc", Severity.Error);
return;
}
if (applicationForm.ClientType == ClientTypes.Confidential)
{
if (editingApplication == null && string.IsNullOrWhiteSpace(applicationForm.ClientSecret))
{
Snackbar.Add("Client Secret là bắt buộc cho Confidential client", Severity.Error);
return;
}
}
if (editingApplication != null)
{
var existingApp = await ApplicationManager.FindByClientIdAsync(editingApplication.ClientId);
if (existingApp != null)
{
var descriptor = new OpenIddictApplicationDescriptor
{
ClientId = applicationForm.ClientId,
DisplayName = applicationForm.DisplayName,
ClientType = applicationForm.ClientType,
ConsentType = applicationForm.ConsentType
};
if (applicationForm.ClientType == ClientTypes.Confidential)
{
if (!string.IsNullOrWhiteSpace(applicationForm.ClientSecret))
{
descriptor.ClientSecret = applicationForm.ClientSecret;
}
}
else if (applicationForm.ClientType == ClientTypes.Public)
{
descriptor.ClientSecret = null;
}
var currentDescriptor = new OpenIddictApplicationDescriptor();
await ApplicationManager.PopulateAsync(currentDescriptor, existingApp);
if (applicationForm.ClientType == ClientTypes.Confidential &&
string.IsNullOrWhiteSpace(applicationForm.ClientSecret))
{
descriptor.ClientSecret = currentDescriptor.ClientSecret;
}
foreach (var uriString in applicationForm.RedirectUris)
{
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
{
descriptor.RedirectUris.Add(uri);
}
else
{
Snackbar.Add($"Redirect URI không hợp lệ: {uriString}", Severity.Error);
return;
}
}
foreach (var uriString in applicationForm.PostLogoutRedirectUris)
{
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
{
descriptor.PostLogoutRedirectUris.Add(uri);
}
else
{
Snackbar.Add($"Post Logout URI không hợp lệ: {uriString}", Severity.Error);
return;
}
}
permissionChecks.Where(x => x.Value).ToList().ForEach(kvp => descriptor.Permissions.Add(kvp.Key));
customScopes.ToList().ForEach(scope => descriptor.Permissions.Add(Permissions.Prefixes.Scope + scope));
requirementChecks.Where(x => x.Value).ToList().ForEach(kvp => descriptor.Requirements.Add(kvp.Key));
await ApplicationManager.UpdateAsync(existingApp, descriptor);
}
}
else
{
var descriptor = new OpenIddictApplicationDescriptor
{
ClientId = applicationForm.ClientId,
DisplayName = applicationForm.DisplayName,
ClientType = applicationForm.ClientType,
ConsentType = applicationForm.ConsentType,
ClientSecret = applicationForm.ClientType == ClientTypes.Confidential ? applicationForm.ClientSecret : null
};
foreach (var uriString in applicationForm.RedirectUris)
{
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
{
descriptor.RedirectUris.Add(uri);
}
}
foreach (var uriString in applicationForm.PostLogoutRedirectUris)
{
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri))
{
descriptor.PostLogoutRedirectUris.Add(uri);
}
}
permissionChecks.Where(x => x.Value).ToList().ForEach(kvp => descriptor.Permissions.Add(kvp.Key));
customScopes.ToList().ForEach(scope => descriptor.Permissions.Add(Permissions.Prefixes.Scope + scope));
requirementChecks.Where(x => x.Value).ToList().ForEach(kvp => descriptor.Requirements.Add(kvp.Key));
await ApplicationManager.CreateAsync(descriptor);
}
Snackbar.Add(editingApplication != null ? "Cập nhật application thành công" : "Tạo application thành công", Severity.Success);
ShowApplicationDialog = false;
await LoadApplicationsAsync();
}
catch (Exception ex)
{
Snackbar.Add($"Lỗi khi lưu application: {ex.Message}", Severity.Error);
}
}
private void CancelApplicationDialog()
{
ShowApplicationDialog = false;
ResetApplicationForm();
}
private async Task DeleteApplication(string clientId)
{
var confirm = await DialogService.ShowMessageBox("Xác nhận xóa", $"Bạn có chắc chắn muốn xóa application '{clientId}'?", yesText: "Xóa", cancelText: "Hủy");
if (confirm == true)
{
try
{
var app = await ApplicationManager.FindByClientIdAsync(clientId);
if (app != null)
{
await ApplicationManager.DeleteAsync(app);
Snackbar.Add("Xóa application thành công", Severity.Success);
await LoadApplicationsAsync();
}
}
catch (Exception ex)
{
Snackbar.Add($"Lỗi khi xóa application: {ex.Message}", Severity.Error);
}
}
}
}