基础信息

1.什么是鉴权授权?
  • 鉴权是验证用户是否拥有访问系统的权利,授权是判断用户是否有权限做一些其他操作。

2.传统的Session 和Cookie
  • 主要用于无状态请求下的的用户身份识别,只不过Session将信息存储在服务端,Cookie将信息存储在客户端。

Session

  1. 在客户端第一次进行访问时,服务端会生成一个Session id返回到客户端

  2. 客户端将Session id存储在本地后续每一次请求都带上这个id

  3. 服务端从接收到的请求中根据Session id在自己存储的信息中识别客户端

Cookie

  1. 在客户端访问服务器时,服务端会在响应中颁发一个Cookie

  2. 客户端会把cookie存储,当再访问服务端时会将cookie和请求一并提交

  3. 服务端会检查cookie识别客户端,并也可以根据需要修改cookie的内容


3.存在的问题

在分布式或集群系统中使用Session

假设现在服务器为了更好的承载和容灾将系统做了分布式和集群,也就是有了N个服务端,那是不是每一个服务端都要具有对每一个客户端的Session或者Cookie的识别能力呢?

这个可以使用Session共享的方式用于Session的识别,但是这并不能解决分布式系统下依然存在这个问题,因为通常每一个分布式系统都由不同的人负责或者跨网络,甚至不同的公司,不可能全部都做session共享吧?这个时候就诞生了一个新的方式,使用Token


4.Token
  • Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌。

执行步骤

  1. 用户向统一的鉴权授权系统发起用户名和密码的校验

  2. 校验通过后会颁发一个Token,用户就拿着颁发的Token去访问其他三方系统

  3. 三方系统可以直接请求鉴权授权系统验证当前Token的合法性,也可以根据对称加密使用秘钥解密Token以验证合法性


.NET Core中鉴权

  • Authentication: 鉴定身份信息,例如用户有没有登录,用户基本信息

  • Authorization: 判定用户有没有权限

1.NET Core鉴权授权基本概念

在NETCORE中鉴权授权是通过AuthenticationHttpContextExtensions扩展类中的实现的HttpContext的扩展方法来完成的

 public static class AuthenticationHttpContextExtensions
{
public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{
context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties);
}
}

它真正的核心在

Microsoft.AspNetCore.Authorization模块,整个流程处理主要包含如下几个关键类

  • IAuthenticationHandlerProvider

负责对用户凭证的验证,提供IAuthenticationHandler处理器给IAuthenticationService用于处理鉴权请求,当然可以自定义处理器

  • IAuthenticationSchemeProvider

选择标识使用的是哪种认证方式

  • IAuthenticationService

提供鉴权统一认证的5个核心业务接口

 public interface IAuthenticationService
{
//查询鉴权
Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme); //登录写入鉴权凭证
Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties); //退出登录清理凭证
Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties); Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties); Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties);
}

在它的实现类AuthenticationService中的SignInAsync方法

配合IAuthenticationHandlerProvider 和IAuthenticationSchemeProvider得到一个IAuthenticationHandler,最终将鉴权写入和读取都由它完成

public virtual async Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{
if (scheme == null)
{
//IAuthenticationSchemeProvider实例
var defaultScheme = await Schemes.GetDefaultSignInSchemeAsync();
scheme = defaultScheme?.Name;
} //IAuthenticationHandlerProvider实例获取处理器
var handler = await Handlers.GetHandlerAsync(context, scheme);
var signInHandler = handler as IAuthenticationSignInHandler; //各自的处理器handler
//例如使用Cookie 就会注入一个CookieAuthenticationHandler
//使用JWT 就注入一个JwtBearerHandler
await signInHandler.SignInAsync(principal, properties);
}

2.使用Cookie默认流程鉴权
  1. 使用中间件加入管道,用于找到鉴权HttpContext.AuthenticateAsync()
   //核心源码就是AuthenticationMiddleware中间件
app.UseAuthentication();
  1. 注入容器,将CookieAuthenticationHandler作为处理逻辑
services.AddAuthentication(options =>
{
//CookieAuthenticationDefaults.AuthenticationScheme == "Cookies"
options.DefaultAuthenticateScheme = "Cookies";
options.DefaultSignInScheme = "Cookies";
}).AddCookie();
  1. 在登录时写入凭证
  • Claims:一项信息,例如工牌的姓名是一个Claims ,工牌号码也是一个Claims

  • ClaimsIdentity:一组Claims 组成的信息,就是一个用户身份信息

  • ClaimsPrincipal:一个用户有多个身份

  • AuthenticationTicket:用户票据,用于包裹ClaimsPrincipal


[AllowAnonymous]
public async Task<IActionResult> Login(string name, string password)
{
if(name!="Admin" && password!="000000")
{
var result = new JsonResult(new{ Result = false,Message = "登录失败"});
return result;
}
//Claims ⫋ ClaimsIdentity ⫋ ClaimsPrincipal
var claimIdentity = new ClaimsIdentity("ClaimsIdentity");
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, name));
claimIdentity.AddClaim(new Claim(ClaimTypes.Address, "地址信息")); AuthenticationProperties ap = new AuthenticationProperties();
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimIdentity);
await base.HttpContext.SignInAsync("Cookies",claimsPrincipal , ap)
return new JsonResult(new{ Result = false,Message = "登录成功"});
}

4.在其他控制器上标记[Authorize]特性,在访问接口框架会自动进行鉴权并将身份信息写入上下文

  • [AllowAnonymous]:匿名可访问

  • [Authorize]:必须登录才可访问


3.自定义IAuthenticationHandler
  1. 实现IAuthenticationHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler三个接口

public class CoreAuthorizationHandler : IAuthenticationHandler
,IAuthenticationSignInHandler, IAuthenticationSignOutHandler
{
public AuthenticationScheme Scheme { get; private set; }
protected HttpContext Context { get; private set; }
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
Scheme = scheme;
Context = context;
return Task.CompletedTask;
} public async Task<AuthenticateResult> AuthenticateAsync()
{
var cookie = Context.Request.Cookies["CustomCookie"];
if (string.IsNullOrEmpty(cookie))
{
return AuthenticateResult.NoResult();
}
AuthenticateResult result = AuthenticateResult
.Success(Deserialize(cookie));
return await Task.FromResult(result);
} public Task ChallengeAsync(AuthenticationProperties properties)
{
return Task.CompletedTask;
} public Task ForbidAsync(AuthenticationProperties properties)
{
Context.Response.StatusCode = 403;
return Task.CompletedTask;
} public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
var ticket = new AuthenticationTicket(user, properties, Scheme.Name);
Context.Response.Cookies.Append("CoreAuthorizationHandlerCookies", Serialize(ticket));
return Task.CompletedTask;
} public Task SignOutAsync(AuthenticationProperties properties)
{
Context.Response.Cookies.Delete("CoreAuthorizationHandlerCookies");
return Task.CompletedTask;
} private AuthenticationTicket Deserialize(string content)
{
byte[] byteTicket = System.Text.Encoding.Default.GetBytes(content);
return TicketSerializer.Default.Deserialize(byteTicket);
}
private string Serialize(AuthenticationTicket ticket)
{
//需要引入 Microsoft.AspNetCore.Authentication
byte[] byteTicket = TicketSerializer.Default.Serialize(ticket);
return Encoding.Default.GetString(byteTicket);
}
}
  1. 在容器中注册自定义的Handler

services.AddAuthenticationCore(options =>
{
options.AddScheme<CoreMvcAuthenticationHandler>("AuthenticationScheme", "AuthenticationScheme");
});

.NET CORE 鉴权的更多相关文章

  1. ASP.NET Core 项目简单实现身份验证及鉴权

    ASP.NET Core 身份验证及鉴权 目录 项目准备 身份验证 定义基本类型和接口 编写验证处理器 实现用户身份验证 权限鉴定 思路 编写过滤器类及相关接口 实现属性注入 实现用户权限鉴定 测试 ...

  2. .NET Core中的鉴权授权正确方式(.NET5)

    一.简介 前后端分离的站点一般都会用jwt或IdentityServer4之类的生成token的方式进行登录鉴权.这里要说的是小项目没有做前后端分离的时站点登录授权的正确方式. 一.传统的授权方式 这 ...

  3. .Net Core使用Ocelot网关(二) -鉴权认证

    前言 上一章已经简单的介绍了ocelot的使用了,但是网关暴露的接口如果什么人都能访问的话安全性就太低啦.所以我们需要去鉴权和认证.这里我们使用identityServer4给我们的网关来鉴权认证. ...

  4. Mongodb 认证鉴权那点事

    [TOC] 一.Mongodb 的权限管理 认识权限管理,说明主要概念及关系 与大多数数据库一样,Mongodb同样提供了一套权限管理机制. 为了体验Mongodb 的权限管理,我们找一台已经安装好的 ...

  5. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

  6. 认证鉴权与API权限控制在微服务架构中的设计与实现(四)

    引言: 本文系<认证鉴权与API权限控制在微服务架构中的设计与实现>系列的完结篇,前面三篇已经将认证鉴权与API权限控制的流程和主要细节讲解完.本文比较长,对这个系列进行收尾,主要内容包括 ...

  7. Spring Boot整合实战Spring Security JWT权限鉴权系统

    目前流行的前后端分离让Java程序员可以更加专注的做好后台业务逻辑的功能实现,提供如返回Json格式的数据接口就可以.像以前做项目的安全认证基于 session 的登录拦截,属于后端全栈式的开发的模式 ...

  8. SpringBoot使用token简单鉴权

    本文使用SpringBoot结合Redis进行简单的token鉴权. 1.简介 刚刚换了公司,所以最近有些忙碌,所以一直没有什么产出,最近朋友问我登录相关的,所以这里先写一篇简单使用token鉴权的文 ...

  9. springboot oauth 鉴权之——password鉴权相当于jwt鉴权模式

    近期一直在研究鉴权方面的各种案例,这几天有空,写一波总结及经验. 第一步:什么是 OAuth鉴权 OAuth2是工业标准的授权协议.OAuth2取代了在2006创建的原始OAuthTM协议所做的工作. ...

随机推荐

  1. SYCOJ157乘二加一

    题目-乘二加一 (shiyancang.cn) 递归写法 #include <bits/stdc++.h> using namespace std; string f(int n) { i ...

  2. 周末撸了个Excel框架,现已开源,yyds!!

    大家好,我是冰河~~ 不管是传统软件企业还是互联网企业,不管是管理软件还是面向C端的互联网应用.都不可避免的会涉及到报表操作,而对于报表业务来说,一个很重要的功能就是将数据导出到Excel. 如果我们 ...

  3. 记一次异步处理导致Jetty Request对象泄漏

    最近排查一个bug,发现了一系列有意思的东西,对「自定义线程池」.「Jetty线程模型」都有了一些新的认识. 本文预计阅读时间10分钟,包括: 问题表现 常见原因筛查 根因与源码分析 最佳实践 一些小 ...

  4. (2)用Micropython将ESP32数据上云

    之前我们尝试过直接把LED点亮并且闪烁. 今天尝试一下将LED的开关状态上云,并可以通过云来进行数据下发. 数据要上云,首先开发板要联网. 首先我们会用 Python的network 库, 在netw ...

  5. 【刷题-PAT】A1108 Finding Average (20 分)

    1108 Finding Average (20 分) The basic task is simple: given N real numbers, you are supposed to calc ...

  6. unity3d录音

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class record : ...

  7. Servlet-概念及实现一个Servlet程序

    Servlet技术 一,Servlet概念 1,Servlet是JavaEE规范之一.规范就是接口 2,Servlet就是JavaWeb三大组件之一.三大组件分别是:Servlet程序.Filter过 ...

  8. 多线程-线程间通信-多生产者多消费者问题解决(notifyAll)

    1 package multithread4; 2 3 /* 4 * 生产者,消费者. 5 * 6 * 多生产者,多消费者的问题. 7 * 8 * if判断标记,只有一次,会导致不该运行的线程运行了. ...

  9. 黑客是如何通过开放的Redis服务入侵服务器的

    0x00 简要说明 百度百科:Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-V ...

  10. Redis 源码简洁剖析 05 - ziplist 压缩列表

    ziplist 是什么 Redis 哪些数据结构使用了 ziplist? ziplist 特点 优点 缺点 ziplist 数据结构 ziplist 节点 pre_entry_length encod ...