Program.cs 配置
builder.Services.AddScoped<AuthenticationStateProvider, WebAuthenticationStateProvider>(); builder.Services.AddCascadingAuthenticationState(); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/Login"; options.LogoutPath = "/Account/Logout"; options.ExpireTimeSpan = TimeSpan.FromMinutes(5); options.SlidingExpiration = true; }); builder.Services.AddAuthorizationCore(); builder.Services.AddScoped<IAuthorizationHandler,WebAuthorizationHandler>(); // 注意顺序 app.UseAuthentication(); app.UseAuthorization();
Routes.razor 修改
<CascadingAuthenticationState> <Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <AuthorizeRouteView Resource="routeData" RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"> <NotAuthorized> @if (context.User.Identity.IsAuthenticated == false) { <RedirectToLogin/> } else { 未授权提示 } </NotAuthorized> </AuthorizeRouteView> <FocusOnNavigate RouteData="routeData" Selector="h1"/> </Found> </Router> </CascadingAuthenticationState>
RedirectToLogin 是自动跳转登录
@inject NavigationManager NavigationManager @code { [CascadingParameter] HttpContext _httpContext { get; set; } = default!; protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); var returnUrl = Uri.EscapeDataString(NavigationManager.Uri); NavigationManager.NavigateTo($"/Account/Login?returnUrl={returnUrl}", forceLoad: true); } }
登录验证
public class WebAuthenticationStateProvider : AuthenticationStateProvider { private readonly IHttpContextAccessor _httpContextAccessor; public WebAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override Task<AuthenticationState> GetAuthenticationStateAsync() { var user = _httpContextAccessor.HttpContext.User ?? new ClaimsPrincipal(new ClaimsIdentity()); return Task.FromResult(new AuthenticationState(user)); } public async Task LoginAsync(UserSession userSession) { await _httpContextAccessor.HttpContext!.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, userSession.Name), new Claim(ClaimTypes.Role, userSession.Role), }, "WebAuth"))); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } public async Task LogoutAsync() { await _httpContextAccessor.HttpContext!.SignOutAsync(); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } }
授权验证
public class WebAuthorizationHandler : AuthorizationHandler<IAuthorizationRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IAuthorizationRequirement requirement) { if (context.User.Identity?.IsAuthenticated != true) { return Task.CompletedTask; } if (context.Resource is Microsoft.AspNetCore.Components.RouteData routeData) { var routeAttr = routeData.PageType.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(RouteAttribute)); if (routeAttr == null) { context.Succeed(requirement); } else { var url = routeAttr.ConstructorArguments[0].Value as string; if (checkUrl(url)) { context.Succeed(requirement); } else { context.Fail(); } } } else if (context.Resource is HttpContext httpContext) { var url = httpContext.Request.Path.Value; if (checkUrl(url)) { context.Succeed(requirement); } else { context.Fail(); } } return Task.CompletedTask; } }
checkUrl 方法中根据需要对url进行授权验证即可