NET6完整项目实战系列第6篇:用户登录番外篇--app.UseAuthentication()和app.UseAuthorization()的使用(下)

要达到最初的设想,需在 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();

第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")    // 错误!          

 

【完】

源码下载

posted @ 2022-07-07 00:40  屏风马  阅读(2411)  评论(1编辑  收藏  举报