【从0开始.NET CORE认证】-3 声明和策略授权

系列

【从0开始.NET CORE认证】-1 认识认证和授权

回顾

Hi,朋友们,我稍微整理了一下,把整个系列放到每篇文章的最前面和最后面,方便大家阅读。

我们简单回顾以下上周讲的内容

  1. 引入了.Net Core自带的Identity框架和EF Core
  2. 在SqlServer数据库中做了数据持久化
  3. 设计了登录/注册等功能

上次我们讲的比较简单。所以说本文就开始写如何对这些用户操作,为这些用户添加某些权限,或者使用策略限制用户访问不同的接口,达到不同的目的(这边文章选读性的)

具体要做的功能是我是下图我箭头指出的框选区域

 

 

 

从本篇开始,会开始精简一些机械化操作,部分操作会用图片来代替GIF图.会在调试、解决错误、运行示例的时候还是使用GIF图 同样,本文还是包含大量GIF图,请耐心等待加载


 

为用户添加声明

还记得我们第一章创建的Demo吗?我们当时引入Claim、Identitty等概念,仔细看一下,我们登录接口(生成Cookie接口)和我们使用.net core Identity接口有什么不同

通过比对,我们很快发现,第一章写的Claims、ClaimsIdentity、ClaimsPrincipal在.Net Core Identity的项目登录中,没有使用到。

如果我们要对一个接口进行限制,例如只有老板才能访问接口。我们在.Net Core Identity写的是完全没有办法实现这个功能的。所以我们需要改造一下。

在Identity中对用户信息操作要使用的是UserManager这个接口,顺便说一句:UserManager是SignInManager的属性,即你可以只引入SignInManager,然后使用SignInManager.UserManager的方式来访问UserManager下面的方法和属性

把代码改成下面

  代码如下

 1 [HttpPost]
 2         public async Task<IActionResult> Login(string username, string password)
 3         {
 4             var user = await _userManager.FindByNameAsync(username);
 5             if (user != null)
 6             {
 7                 var signResult = await _signInManager.PasswordSignInAsync(user, password, false, false);
 8                 if (signResult.Succeeded)
 9                 {
10                     var claims = new List<Claim>()
11                     {
12                         new Claim(ClaimTypes.Name,user.UserName),
13                         new Claim("Age","15"),
14                     };
15                     var r = await _signInManager.UserManager.AddClaimsAsync(user, claims);
16                     if (r.Succeeded)
17                     {
18                         return RedirectToAction("Secert");
19                     }
20                 }
21             }
22             return RedirectToAction("Register");
23         }

 从图中可以看到,我们跟第一章一样,给用户添加了Claim,然后调用了UserManager下面的AddClaimsAsync的方法,传递的参数是我们从数据库中获取出来的的User类型是IdentityUser和我们定义的Claims的集合。题外话:多个Claim组合然后找个签发机构,就会变成什么?

然后我们为接口套上一层验证机制,只需要在Authorize的标签上赋值即可。为Secect接口加上验证。并且在Secert.cshtml将该用户的Claim显示出来

代码如下

1 <h1>这需要授权访问的页面</h1>
2 
3 
4 @foreach (var item in User.Claims)
5 {
6     <p>@item.Type.Split('/')[item.Type.Split('/').Length - 1]:@item.Value</p>
7 }

运行结果如下

修改或删除用户的Claim

我们添加一个可以修改用户的页面,将上次的Update.cshtml页面搬出来修改一下

1 <form formaction="/Home/ModifyUserClaim" method="post">
2     <input name="username" value="@User.Claims.Where(i=>i.Type==ClaimTypes.Name).Select(p=>p.Value).FirstOrDefault()" />
3     <button>确认修改</button>
4 </form>

修改接口:

1 [HttpPost]
2 public async Task<IActionResult> ModifyUserClaim(string username)
3 {
4    var newclaim =  new Claim(ClaimTypes.Name, "qqq");
5    var user = await _userManager.FindByNameAsync(username);
6    await _signInManager.UserManager.ReplaceClaimAsync(user, User.Claims.Where(u=>u.Type==ClaimTypes.Name).First(), newclaim);
7    return View("Update");
8 }

  删除接口

1 [HttpPost]
2 public async Task<IActionResult> RemoveUserClaim(string username)
3 {
4    var user = await _userManager.FindByNameAsync(username);
5    await _signInManager.UserManager.RemoveClaimAsync(user, User.Claims.Where(u => u.Type == ClaimTypes.Name).First());
6    return View("Update");
7 }

 他们分别调用了ReplaceClaimAsync和RemoveClaimAsync。其余操作没什么差异

基于策略的授权

这个应用场景非常多,日常生活中肯定会碰到多多少少需要权限访问接口的业务。例如:公司员工信息表中,有些员工填写了出生日期,有些没有,填写的人可以访问生日福利接口,没填写的人拒绝访问。又或者说:没填写的人,但是他的职位是总经理以上级别,就可以不需要填写出生日期就可以访问这个接口。等等诸如此类的权限控制。所以我们这么做

添加一个接口,和一个页面,加上Authorize(Policy ="HasBirthDay") 就是指定一个授权策略,这个授权策略名为HasBirthDay

 然后添加页面

 运行:很显然,会出错,提示没有找到一个名为HasBirthDay的授权策略。

我们在Startp.cs中加入这个授权策略

代码如下

1  services.AddAuthorization(config => {
2      var defaultPolicyBuilder = new AuthorizationPolicyBuilder();
3      defaultPolicyBuilder.RequireClaim(ClaimTypes.DateOfBirth);
4      config.AddPolicy("HasBirthDay", defaultPolicyBuilder.Build());
5 });

再次运行试试看:因为我们当面登录的用户中没有给与DateOfBirth的Claims所以会被强制跳转到拒绝授权的页面。

我们给当前的用户加上DateOfBirth,试试看能不能访问,在Login出增加一行Claims

运行:可以看到,成功运行小提示:请先清空浏览器的Cookies,否则还是会被拒绝的。

 

基于角色的授权

在.net中,有一个非常方便的授权模式就是基于角色的授权,例如,普通用户不能访问,管理员能访问,老板能访问,员工不能访问。基于角色的授权其实就是基于策略的授权的演化,本身属于策略的一部分。稍微改动一下代码,把Policy换成了Role 值从HasBirthDay改成了Boss

运行试试看,很显然,我们又被拒绝了。

 

我们在登录的时候增加以下代码:

运行:可以看到,成功运行小提示:请先清空浏览器的Cookies,否则还是会被拒绝的。

 

基于权限的认证显然比基于策略的使用方便很多,这也是.net 认证系统中非常闻名的一个方式,对付单个接口非常有用

好了,本期文章就写到这里我们下次再见

【从0开始.NET CORE认证】-1 认识认证和授权

【从0开始.NET CORE认证】-2 使用.Net Core Identity和EF Core

posted @ 2020-02-22 22:02  寂寞空庭春欲晚  阅读(780)  评论(0编辑  收藏  举报