要达到最初的设想,需在 Program.cs中启用认证中间件服务 : app.UseAuthentication();
同时给 builder.Services.AddAuthentication( ) 处理程序设置对应的方案,如下(红色部分代码):
using Microsoft.AspNetCore.Authentication.Cookies; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); // Add services to the container. builder.Services.AddRazorPages(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. // You may want to change this for production scenarios, // see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); //app.UseAuthorization(); app.MapRazorPages(); app.Run();
编译后重新运行,在登录页面输入 admin/123 后运行结果如下:
可以看到用户已通过了认证,声明中的值也都打印出来了,至此,整个登录认证过程就完成了。
补充:前面提到“方案”这个词,对应的英文是 Scheme , 那么什么是方案呢?看微软官方文档是如何描述的:
身份验证方案及处理程序的功能在官方文档描述如下:
至于如何去自定义,后续再展开。
接下来,我们来看如何实现不同的角色访问不同的页面。
虽然前面实现了认证,能读取声明中的信息,但以admin的身份登录后是可以访问 UserIndex 页面的,反之亦然,要实现admin账号
只能访问adminmng目录下的页面,步骤如下:
第1步:在Program.cs中启用授权中间件并设置无权限访问时要跳转的页面,本例中跳转到 Forbidden.cshtml ,代码件红色字体部分:
using Microsoft.AspNetCore.Authentication.Cookies;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => {
//滑动过期
options.SlidingExpiration = true;
//滑动过期时间30分钟,即30分钟内没有访问页面就过期
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
//无权限访问时跳转到的页面,Pages目录下要有Forbidden.cshtml页面
options.AccessDeniedPath = "/forbidden";
});
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days.
// You may want to change this for production scenarios,
// see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();//启用授权中间件
app.UseAuthorization();
app.MapRazorPages();
app.Run();
using Microsoft.AspNetCore.Authentication.Cookies; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { //滑动过期 options.SlidingExpiration = true; //滑动过期时间30分钟,即30分钟内没有访问页面就过期 options.ExpireTimeSpan = TimeSpan.FromMinutes(30); //无权限访问时跳转到的页面,Pages目录下要有Forbidden.cshtml页面 options.AccessDeniedPath = "/forbidden"; }); // Add services to the container. builder.Services.AddRazorPages(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. // You may want to change this for production scenarios, // see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); //启用授权中间件 app.UseAuthorization(); app.MapRazorPages(); app.Run();
第2步:在 Pages 目录下新增 Forbidden.cshtml ,页面代码如下:
@page @model WebApplication1.Pages.ForbiddenModel @{ } <div>没有权限访问此页面!</div>
第3步:给要设置权限的页面 Model 增加Authorize特性,如下(见红色字体):
AdminIndex.cshtml.cs 页面如下:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.RazorPages; namespace WebApplication1.Pages.AdminMng { [Authorize(Roles ="AdminRole")] public class AdminIndexModel : PageModel { public void OnGet() { } } }
UserIndex.cshtml.cs 页面如下:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.RazorPages; namespace WebApplication1.Pages.UserMng { [Authorize(Roles = "UserRole")] public class UserIndexModel : PageModel { public void OnGet() { } } }
至此配置完毕, 最重要的是在登录声明中一定要包含 new Claim(ClaimTypes.Role, roleName) 语句 !
注意:和 WEBAPI 不同,RazorPages 的角色授权只能是整个页面(这里是UserIndexModel),不可以具体到页面中的某个方法,
而WebAPI既可以是Controller,也可以是Controller中的某个方法(Action)。
解决方案目录如下:
编译后运行,访问以admin的账号登录,页面如下:
在浏览器的地址栏把网址改成 usermng/userindex 后按 enter 键 ,页面如下:
可以看到:
1. 网址变成了 forbidden ,并且我们欲访问的页面 usermng/userindex 变成了查询参数 ReturnUrl 的值;
2. 显示了 Forbidden.cshtml 页面的值,这是我们在 Program.cs 的 AddCookie( ) 方法中设置的;
3. 按下 enter 键后访问的页面返回了 302 的状态码, 然后页面发生了跳转;
4. cookie 信息没有改变;
=================结束分割线==============
问题: 如果有一个页面 ,比如 Pages/Common/ModifyPassword.cshtml 只要登录用户都可以访问,不需要区分角色,该如何设置呢?
有2种方法:
其一:在 ModifyPassword.cshtml.cs 中增加 Authorize 特性且不要传递 Roles 属性值,如下(红色字体部分):
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.RazorPages; namespace WebApplication1.Pages.Common { [Authorize] public class ModifyPasswordModel : PageModel { public void OnGet() { } } }
重新编译后清除cookie访问如下:
其二:在 program.cs 中增加 授权约定(authorization conventions) ,如下(红色字体部分):
using Microsoft.AspNetCore.Authentication.Cookies; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { //滑动过期 options.SlidingExpiration = true; //滑动过期时间30分钟,即30分钟内没有访问页面就过期 options.ExpireTimeSpan = TimeSpan.FromMinutes(30); //无权限访问时跳转到的页面,Pages目录下要有Forbidden.cshtml页面 options.AccessDeniedPath = "/forbidden"; //无认证时跳转的页面 options.LoginPath = "/login"; }); // Add services to the container. builder.Services.AddRazorPages(options => { //针对文件设置访问权限 options.Conventions.AuthorizePage("/Common/ModifyPasswrod"); //针对文件夹设置访问权限 //options.Conventions.AuthorizeFolder("/Common"); //以下设置可以针对文件或文件夹取消访问权限验证 //options.Conventions.AllowAnonymousToPage("/Common/ModifyPasswrod"); //options.Conventions.AllowAnonymousToFolder("/Common"); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. // You may want to change this for production scenarios, // see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
编译后访问,和第一种方式的效果相同。。。
注意:文件夹和页面授权的包含关系如下:
* 先指定页面文件夹需要授权,然后指定该文件夹中的页面允许匿名访问,这样操作是有效的:
.AuthorizeFolder("/Common").AllowAnonymousToPage("/Common/XxxPage") // 正确 !
* 不可以先为匿名访问声明页面文件夹,然后在该文件夹中指定需要授权的页面
.AllowAnonymousToFolder("/Common").AuthorizePage("/Common/XxxPage") // 错误!
【完】