blog-details

Giới thiệu Xác thực là quá trình xác định hoặc cấp cho cá nhân quyền truy cập vào hệ thống hoặc người dùng dựa trên danh tính của họ. Bài viết này trình bày cách thêm Ủy quyền dựa trên chính sách và vai trò tùy chỉnh trong ASP.NET Core 3.0 Trong trường hợp Xác thực đơn giản, chúng tôi thường sử dụng tên người dùng và mật khẩu để đăng nhập và dựa vào đó chúng tôi sẽ cung cấp quyền truy cập vào ứng dụng, nhưng trong trường hợp này, người dùng có thể truy cập tất cả các tài nguyên của ứng dụng. Bằng cách sử dụng quy trình Ủy quyền dựa trên Chính sách & Vai trò, chúng tôi có thể cung cấp quyền truy cập vào khu vực ứng dụng cụ thể cho người dùng dựa trên Vai trò / Chính sách của người dùng. Trong phần trình diễn này, tôi sẽ sử dụng cookie để lưu trữ thông tin người dùng. Độc giả có thể sử dụng cơ sở dữ liệu để lưu trữ thông tin người dùng. Điều kiện tiên quyết Cài đặt .NET Core 3.x trở lên SDK từ đây. Cài đặt phiên bản mới nhất của Visual Studio 2019 Community Edition từ đây.

Các bước để tạo một ứng dụng web Vui lòng kiểm tra bài viết hiện tại của tôi, Xác thực cookie trong .NET Core 3.0 để thiết lập dự án. Ở đây tôi đã giải thích từng bước làm thế nào để tạo dự án? và làm thế nào để quản lý xác thực? Mã cho ủy quyền cơ bản Nếu bạn muốn thêm Xác thực đơn giản và chỉ muốn xác định Vai trò / Chính sách bằng thẻ ủy quyền để ủy quyền cho hành động / bộ điều khiển như trong cú pháp dưới đây, thì bạn có thể đi với cấu hình đơn giản. AuthorizationPolicyBuilderclass giúp bạn đạt được yêu cầu này.

Add Authorize tag on controller with Policy/Role

[Authorize(Policy = "UserPolicy")]  

[Authorize(Roles = "Admin")]  

public class HomeController : Controller  

{  

}  

 Add Authorize tag on action with Policy/Role

[Authorize(Policy = "UserPolicy")]  

public ActionResult UsersPolicy()  

{  

    var uses = new Users();  

    return View("Users", uses.GetUsers());  

}  

  

[Authorize(Roles = "User")]  

public ActionResult UsersRole()  

{  

    var uses = new Users();  

    return View("Users", uses.GetUsers());  

}  

Update Startup.cs file with below code

using System.Security.Claims;  
using Microsoft.AspNetCore.Authorization;  
using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.Configuration;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Hosting;  
  
namespace CookieAuthenticationDemo  
{  
    public class Startup  
    {  
        public Startup(IConfiguration configuration)  
        {  
            Configuration = configuration;  
        }  
  
        public IConfiguration Configuration { get; }  
  
        public void ConfigureServices(IServiceCollection services)  
        {  
            services.AddAuthentication("CookieAuthentication")  
                 .AddCookie("CookieAuthentication", config =>  
                 {  
                     config.Cookie.Name = "UserLoginCookie"; // Name of cookie   
                     config.LoginPath = "/Login/UserLogin"; // Path for the redirect to user login page  
                 });  
  
            services.AddAuthorization(config =>  
            {  
                var userAuthPolicyBuilder = new AuthorizationPolicyBuilder();  
                config.DefaultPolicy = userAuthPolicyBuilder  
                                    .RequireAuthenticatedUser()  
                                    .RequireClaim(ClaimTypes.DateOfBirth)  
                                    .Build();  
            });  
            services.AddControllersWithViews();  
        }  
  
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
            if (env.IsDevelopment())  
            {  
                app.UseDeveloperExceptionPage();  
            }  
            else  
            {  
                app.UseExceptionHandler("/Home/Error");  
                app.UseHsts();  
            }  
            app.UseHttpsRedirection();  
            app.UseStaticFiles();  
  
            app.UseRouting();  
             
            app.UseAuthentication();  
  
            app.UseAuthorization();  
  
            app.UseEndpoints(endpoints =>  
            {  
                endpoints.MapControllerRoute(  
                    name: "default",  
                    pattern: "{controller=Home}/{action=Index}/{id?}");  
            });  
        }  
    }  
}  

Tích hợp Trình xử lý ủy quyền tùy chỉnh

Bước 1

Tạo một thư mục mới với tên CustomHandler và thêm các lớp bên dưới vào đó.

Lớp 1 - AuthorizationPolicyBuilderExtension: Lớp tĩnh do người dùng định nghĩa để thêm chính sách mới cho Ủy quyền bằng AuthorizationPolicyBuilder.

Lớp 2 - CustomUserRequireClaim: Lớp do người dùng xác định kế thừa từ giao diện IAuthorizationRequonth. Giao diện IAuthorizationRequonth không chứa bất kỳ phương thức nào. Đây là một dịch vụ đánh dấu trống.

Lớp 3 - Chính sáchAuthorizationHandler: Lớp do người dùng định nghĩa kế thừa từ lớp AuthorizationHandler. Phương thức HandleRequonthAsync của lớp AuthorizationHandler

giúp xác thực người dùng dựa trên chính sách.

Lớp 4 - RolesAuthorizationHandler: Giống như lớp Chính sách AuthorizationHandler. Lớp này giúp xác thực người dùng dựa trên Vai trò.

Mã cho CustomUserRequireClaim: Đặt các dòng mã dưới đây vào lớp CustomUserRequireClaim.

using Microsoft.AspNetCore.Authorization;  
using System.Linq;  
using System.Threading.Tasks;  
  
namespace CookieAuthenticationDemo.CustomHandler  
{  
    public class CustomUserRequireClaim : IAuthorizationRequirement  
    {  
        public string ClaimType { get; }  
        public CustomUserRequireClaim(string claimType)  
        {  
            ClaimType = claimType;  
        }  
    }  
}  

 

Code for AuthorizationPolicyBuilderExtension - Put the below lines of code intoAuthorizationPolicyBuilderExtension class.

using Microsoft.AspNetCore.Authorization;  
  
namespace CookieAuthenticationDemo.CustomHandler  
{  
    public static class AuthorizationPolicyBuilderExtension  
    {  
        public static AuthorizationPolicyBuilder UserRequireCustomClaim(this AuthorizationPolicyBuilder builder, string claimType)  
        {  
            builder.AddRequirements(new CustomUserRequireClaim(claimType));  
            return builder;  
        }  
    }  
}  

Code for PoliciesAuthorizationHandler - Put the below lines of code intoPoliciesAuthorizationHandler class.

using Microsoft.AspNetCore.Authorization;  
using System.Linq;  
using System.Threading.Tasks;  
  
namespace CookieAuthenticationDemo.CustomHandler  
{  
    public class PoliciesAuthorizationHandler : AuthorizationHandler<CustomUserRequireClaim>  
    {  
        protected override Task HandleRequirementAsync(  
            AuthorizationHandlerContext context,  
            CustomUserRequireClaim requirement)  
        {  
            if (context.User == null || !context.User.Identity.IsAuthenticated)  
            {  
                context.Fail();  
                return Task.CompletedTask;  
            }  
  
            var hasClaim = context.User.Claims.Any(x => x.Type == requirement.ClaimType);  
  
            if (hasClaim)  
            {  
                context.Succeed(requirement);  
                return Task.CompletedTask;  
            }  
  
            context.Fail();  
            return Task.CompletedTask;  
        }  
    }  
}  

Code for RolesAuthorizationHandler - Put the below lines of code intoRolesAuthorizationHandler class.

using CookieAuthenticationDemo.Models;  
using Microsoft.AspNetCore.Authorization;  
using Microsoft.AspNetCore.Authorization.Infrastructure;  
using System.Linq;  
using System.Threading.Tasks;  
  
namespace CookieAuthenticationDemo.CustomHandler  
{  
    public class RolesAuthorizationHandler : AuthorizationHandler<RolesAuthorizationRequirement>, IAuthorizationHandler  
    {  
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,  
                                                       RolesAuthorizationRequirement requirement)  
        {  
            if (context.User == null || !context.User.Identity.IsAuthenticated)  
            {  
                context.Fail();  
                return Task.CompletedTask;  
            }  
  
            var validRole = false;  
            if (requirement.AllowedRoles == null ||  
                requirement.AllowedRoles.Any() == false)  
            {  
                validRole = true;  
            }  
            else  
            {  
                var claims = context.User.Claims;  
                var userName = claims.FirstOrDefault(c => c.Type == "UserName").Value;  
                var roles = requirement.AllowedRoles;  
  
                validRole = new Users().GetUsers().Where(p => roles.Contains(p.Role) && p.UserName == userName).Any();  
            }  
  
            if (validRole)  
            {  
                context.Succeed(requirement);  
            }  
            else  
            {  
                context.Fail();  
            }  
            return Task.CompletedTask;  
        }  
    }  
}  

Changes In Users class - Update Users class as I mentioned. I have added Role and DateOfBirth extra properties here.

using System.Collections.Generic;  
  
namespace CookieAuthenticationDemo.Models  
{  
    public class Users  
    {  
        public int Id { get; set; }  
        public string UserName { get; set; }  
        public string Name { get; set; }  
        public string EmailId { get; set; }  
        public string Password { get; set; }  
        public string Role { get; set; }  
        public string DateOfBirth { get; set; }  
  
        public IEnumerable<Users> GetUsers()  
        {  
            return new List<Users>() { new Users { Id = 101, UserName = "anet", Name = "Anet", EmailId = "[email protected]", Password = "anet123", Role="Admin" , DateOfBirth  = "01/01/2012"} };  
        }  
    }  
}  

 

Changes In LoginController class - Update LoginController class as  I mention. I have added UserName and DateOfBirth extra claims here. Also, I have added UserAccessDenied action method. If the user has no policy/role then user will redirect to AccessDenied Page. 

using CookieAuthenticationDemo.Models;  
using Microsoft.AspNetCore.Authentication;  
using Microsoft.AspNetCore.Mvc;  
using System.Collections.Generic;  
using System.Linq;  
using System.Security.Claims;  
  
namespace CookieAuthenticationDemo.Controllers  
{  
    public class LoginController : Controller  
    {  
        [HttpGet]  
        public ActionResult UserLogin()  
        {  
            return View();  
        }  
  
        [HttpPost]  
        public ActionResult UserLogin([Bind] Users userModel)  
        {  
            // username = anet  
            var user = new Users().GetUsers().Where(u => u.UserName == userModel.UserName).SingleOrDefault();  
  
            if (user != null)  
            {  
                var userClaims = new List<Claim>()  
                {  
                    new Claim("UserName", user.UserName),  
                    new Claim(ClaimTypes.Name, user.Name),  
                    new Claim(ClaimTypes.Email, user.EmailId),  
                    new Claim(ClaimTypes.DateOfBirth, user.DateOfBirth),  
                    new Claim(ClaimTypes.Role, user.Role)  
                 };  
  
                var userIdentity = new ClaimsIdentity(userClaims, "User Identity");  
  
                var userPrincipal = new ClaimsPrincipal(new[] { userIdentity });  
                HttpContext.SignInAsync(userPrincipal);  
  
                return RedirectToAction("Index", "Home");  
            }  
  
            return View(user);  
        }  
  
        [HttpGet]  
        public ActionResult UserAccessDenied()  
        {  
            return View();  
        }  
    }  
}  

 

Add view for UserAccessDenied - Add a new view for the UserAccessDenied method and put the below lines of code into it.

<div class="alert-danger">  
    <h1>Access Denied </h1>  
    <h3>You dont have permission to view this resource.</h3>  
</div>  

 

Thay đổi trong lớp HomeContoder - Cập nhật lớp HomeContoder như tôi đã đề cập. Tôi đã cập nhật thẻ ủy quyền Authorize với Chính sách và Vai trò.

using CookieAuthenticationDemo.Models;  
using Microsoft.AspNetCore.Authorization;  
using Microsoft.AspNetCore.Mvc;  
  
namespace CookieAuthenticationDemo.Controllers  
{  
    public class HomeController : Controller  
    {  
        public IActionResult Index()  
        {  
            return View();  
        }  
  
        [Authorize]  
        public ActionResult Users()  
        {  
            var uses = new Users();  
            return View(uses.GetUsers());  
        }  
  
         [Authorize(Policy = "UserPolicy")]  
        public ActionResult UsersPolicy()  
        {  
            var uses = new Users();  
            return View("Users", uses.GetUsers());  
        }  
  
        [Authorize(Roles = "User")]  
        public ActionResult UsersRole()  
        {  
            var uses = new Users();  
            return View("Users", uses.GetUsers());  
        }  
         
        [Authorize(Roles = "Admin")]  
        public ActionResult AdminUser()  
        {  
            var uses = new Users();  
            return View("Users", uses.GetUsers());  
        }  
  
    }  
}  

 

Thay đổi trong lớp Khởi động - Cập nhật lớp Khởi động như tôi đề cập bên dưới. Kiểm tra phương thức AddPolicy để biết cách tôi thêm khiếu nại cho chính sách do người dùng xác định. Ngoài ra, tôi đã đăng ký hai dịch vụ xử lý Chính sách AuthorizationHandler RolesAuthorizationHandler của loại IAuthorizationHandler.

using System.Security.Claims;  
using CookieAuthenticationDemo.CustomHandler;  
using Microsoft.AspNetCore.Authorization;  
using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.Configuration;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Hosting;  
  
namespace CookieAuthenticationDemo  
{  
    public class Startup  
    {  
        public Startup(IConfiguration configuration)  
        {  
            Configuration = configuration;  
        }  
  
        public IConfiguration Configuration { get; }  
  
        public void ConfigureServices(IServiceCollection services)  
        {  
            services.AddAuthentication("CookieAuthentication")  
                 .AddCookie("CookieAuthentication", config =>  
                 {  
                     config.Cookie.Name = "UserLoginCookie"; // Name of cookie     
                     config.LoginPath = "/Login/UserLogin"; // Path for the redirect to user login page    
                     config.AccessDeniedPath = "/Login/UserAccessDenied";  
                 });  
  
            services.AddAuthorization(config =>  
            {  
                config.AddPolicy("UserPolicy", policyBuilder =>  
                {  
                    policyBuilder.UserRequireCustomClaim(ClaimTypes.Email);  
                    policyBuilder.UserRequireCustomClaim(ClaimTypes.DateOfBirth);  
                });  
            });  
  
            services.AddScoped<IAuthorizationHandler, PoliciesAuthorizationHandler>();  
            services.AddScoped<IAuthorizationHandler, RolesAuthorizationHandler>();  
  
            services.AddControllersWithViews();  
        }  
  
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
            if (env.IsDevelopment())  
            {  
                app.UseDeveloperExceptionPage();  
            }  
            else  
            {  
                app.UseExceptionHandler("/Home/Error");  
                app.UseHsts();  
            }  
            app.UseHttpsRedirection();  
            app.UseStaticFiles();  
  
            app.UseRouting();  
  
            // who are you?  
            app.UseAuthentication();  
  
            // are you allowed?  
            app.UseAuthorization();  
  
            app.UseEndpoints(endpoints =>  
            {  
                endpoints.MapControllerRoute(  
                    name: "default",  
                    pattern: "{controller=Home}/{action=Index}/{id?}");  
            });  
        }  
    }  
}  

 

Thay đổi trong trang _Layout.cshtml - Cập nhật _Layout.cshtml như tôi đề cập dưới đây.

  1. <!DOCTYPE html>  
    <html lang="en">  
    <head>  
        <meta charset="utf-8" />  
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />  
        <title>@ViewData["Title"] - CookieAuthenticationDemo</title>  
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />  
        <link rel="stylesheet" href="~/css/site.css" />  
    </head>  
    <body>  
        <header>  
            <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">  
                <div class="container">  
                    <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">My Application</a>  
                    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"  
                            aria-expanded="false" aria-label="Toggle navigation">  
                        <span class="navbar-toggler-icon"></span>  
                    </button>  
                    <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">  
                        <ul class="navbar-nav flex-grow-1">  
                            <li class="nav-item">  
                                <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>  
                            </li>  
                            <li class="nav-item">  
                                <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="UsersPolicy">Users Policy</a>  
                            </li>  
                            <li class="nav-item">  
                                <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="UsersRole">Users Role</a>  
                            </li>  
                        </ul>  
                    </div>  
                </div>  
            </nav>  
        </header>  
        <div class="container">  
            <main role="main" class="pb-3">  
                @RenderBody()  
            </main>  
        </div>  
      
        <footer class="border-top footer text-muted">  
            <div class="container">  
                © 2020 - CookieAuthenticationDemo - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>  
            </div>  
        </footer>  
        <script /images/blog/47a411cef0050e1ee86868da3ecd33e.jpg
        <script /images/blog/47a411cef0050e1ee86868da3ecd33e.jpg
        <script /images/blog/47a411cef0050e1ee86868da3ecd33e.jpg
        @RenderSection("Scripts", required: false)  
    </body>  
    </html>  

     

Run your application/ Khởi chạy ứng dụng

Sau khi chạy thành công ứng dụng của bạn, đầu ra của ứng dụng của bạn sẽ giống như màn hình bên dưới,

 

Policy-Based And Role-Based Authorization In ASP.NET Core 3.0 Using Custom Handler

Nhấp vào tab UsersPolicy để kiểm tra xem người dùng có quyền truy cập ở đây hay không.

Đầu tiên, nó sẽ chuyển hướng đến trang đăng nhập để xác thực người dùng,

Policy-Based And Role-Based Authorization In ASP.NET Core 3.0 Using Custom Handler

Nhập tên người dùng là "anet" và mật khẩu "anet" để đăng nhập. Sau khi đăng nhập thành công, bây giờ hãy nhấp vào tab Chính sách người dùng và kiểm tra kết quả. Bây giờ người dùng có thể dễ dàng xem thông tin như dưới đây:

 

Policy-Based And Role-Based Authorization In ASP.NET Core 3.0 Using Custom Handler

Now click on the Users Role tab. Here, the user cannot access that information and is redirected to the access denied page. I have given  Admin role to the user, and for UserRole action method I have mentioned  User role in Authorization tag,

 

Policy-Based And Role-Based Authorization In ASP.NET Core 3.0 Using Custom Handler

 

Policy-Based And Role-Based Authorization In ASP.NET Core 3.0 Using Custom Handler

Tóm lại

Trong bài viết này, tôi đã thảo luận về cách thêm Ủy quyền dựa trên chính sách và vai trò tùy chỉnh trong ASP.NET Core 3.x Chúng tôi cũng đã tạo một Chính sách AuthorizationHandler để xử lý các chính sách và RolesAuthorizationHandler cho các vai trò. Tôi hy vọng điều này sẽ giúp người đọc hiểu cách triển khai trình xử lý ủy quyền tùy chỉnh trong bất kỳ ứng dụng nào. Vui lòng tìm mã đính kèm để hiểu rõ hơn.

 

Đánh giá bài viết