完成了《AD 密碼驗證》與《AD 密碼修改》兩個 API 後,接下來用 .NET MAUI Blazor 來寫桌面端的程式。稍微瞭解了 Blazor 後,覺得好神奇,感覺就是把網頁塞進應用程式裡面,運行時還可以在「工作管理員」看到背後有 Edge 的相關元件在運行,然後按 F12 還會有開發者工具視窗!不過這也讓我衍生了一點安全性的疑慮。但整體感覺還是挺特別的,剛好我對網頁語法比較熟,搭配 Razor 來設計 UI 畫面,感覺親切不少。
程式的結構是兩個頁面,第一個頁面是 AD 密碼驗證,通過後才會導到 AD 密碼變更頁面。
《專案範本》
- .NET MAUI Blazor 應用程式
《套件》
- bootstrap
Services/PasswordManagementService.cs
using System.Net.Http.Json;
namespace NTool.Services
{
public class PasswordManagementService(HttpClient httpClient)
{
public async Task<bool> ValidateAsync(string username, string password)
{
var request = new { Username = username, Password = password };
var response = await httpClient.PostAsJsonAsync("Password/Validate", request);
return response.IsSuccessStatusCode;
}
public async Task<bool> ChangeAsync(string username, string password, string newPassword)
{
var request = new { Username = username, OldPassword = password, NewPassword = newPassword };
var response = await httpClient.PostAsJsonAsync("Password/ChangeSdsP", request);
return response.IsSuccessStatusCode;
}
}
}
Components/Pages/PasswordValidation.razor
@page "/"
@using NTool.Services
@using NTool.Models
@inject PasswordManagementService PasswordManagementService
@inject ValidRequest ValidRequest
@inject NavigationManager Navigation
<h3 class="mt-5 text-center">AD 密碼變更工具</h3>
<p>請驗證帳號密碼</p>
<EditForm Model="ValidRequest" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label for="username">使用者登入名稱</label>
<InputText id="username" @bind-Value="ValidRequest.Username" placeholder="輸入帳號" />
</div>
<div>
<label for="password">密碼</label>
<InputText id="password" @bind-Value="ValidRequest.Password" placeholder="輸入密碼" type="password" />
</div>
<button type="submit">驗證</button>
</EditForm>
<p>@resultMessage</p>
@code {
private string resultMessage = string.Empty;
private async Task HandleValidSubmit()
{
var isValid = await PasswordManagementService.ValidateAsync(ValidRequest.Username, ValidRequest.Password);
if (isValid)
{
Navigation.NavigateTo("/PasswordChange");
}
else
{
resultMessage = "驗證失敗。";
}
}
}
Components/Pages/PasswordChange.razor
@page "/PasswordChange"
@using NTool.Models
@using NTool.Services
@inject PasswordManagementService PasswordManagementService
@inject HttpClient Http
@inject NavigationManager Navigation
@inject ChangeRequest ChangeRequest
@inject ValidRequest ValidRequest
<h3 class="mt-5 text-center">AD 密碼變更工具</h3>
<p>@Message</p>
<EditForm Model="ChangeRequest" OnValidSubmit="HandleChangeSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label for="newPassword">新密碼</label>
<InputText id="newPassword" @bind-Value="ChangeRequest.NewPassword" placeholder="輸入新密碼" type="password" />
</div>
<div>
<label for="confirmPassword">確認新密碼</label>
<InputText id="confirmPassword" @bind-Value="ChangeRequest.ConfirmPassword" placeholder="確認新密碼" type="password" />
</div>
<button type="submit">變更密碼</button>
</EditForm>
@code {
private string Message { get; set; } = "驗證成功!請變更密碼";
private async Task HandleChangeSubmit()
{
var isValid = await PasswordManagementService.ChangeAsync(ValidRequest.Username, ValidRequest.Password, ChangeRequest.NewPassword);
if (isValid)
{
Message = "密碼變更成功。";
ValidRequest.Password = string.Empty;
ChangeRequest.NewPassword = string.Empty;
ChangeRequest.ConfirmPassword = string.Empty;
// Navigation.NavigateTo("/");
}
else
{
Message = "密碼變更失敗。";
ChangeRequest.NewPassword = string.Empty;
ChangeRequest.ConfirmPassword = string.Empty;
}
}
}
Models/PasswordModel.cs
using System.ComponentModel.DataAnnotations;
namespace NTool.Models
{
public class ValidRequest
{
[Required(ErrorMessage = "[使用者登入名稱] 為必填欄位。")]
public required string Username { get; set; }
[Required(ErrorMessage = "[密碼] 為必填欄位。")]
public required string Password { get; set; }
}
public class ChangeRequest
{
[Required(ErrorMessage = "[新密碼] 為必填欄位。")]
public required string NewPassword { get; set; }
[Required(ErrorMessage = "[確認新密碼] 為必填欄位。")]
[Compare("NewPassword", ErrorMessage = "[新密碼] 與 [確認新密碼] 不相符。")]
public required string ConfirmPassword { get; set; }
}
}
MauiProgram.cs
using Microsoft.Extensions.Logging;
using NTool.Services;
using NTool.Models;
namespace NTool
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
builder.Services.AddMauiBlazorWebView();
#if DEBUG
builder.Services.AddBlazorWebViewDeveloperTools();
builder.Logging.AddDebug();
#endif
// 注入 HttpClient,並設定 API 的基底網址
builder.Services.AddScoped(sp => new HttpClient
{
BaseAddress = new Uri("https://api.abc.com/ad/")
});
// 注入 Services、Models
builder.Services.AddScoped<PasswordManagementService>();
builder.Services.AddScoped<ValidRequest>();
builder.Services.AddScoped<ChangeRequest>();
return builder.Build();
}
}
}
wwwroot/css/styles.css
body {
background-color: #f0f8ff; /* 淡粉藍背景色 */
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
form {
max-width: 400px;
margin: 50px auto;
background: white;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
padding: 20px;
}
form div {
margin-bottom: 15px;
}
form label {
display: block;
font-weight: bold;
margin-bottom: 5px;
}
form input {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
form button {
width: 100%;
padding: 10px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
form button:hover {
background-color: #45a049;
}
p {
text-align: center;
color: #ff0000;
font-weight: bold;
}
《結果畫面》









發佈留言