












这两个协议是用于授权和认证的使用最广泛的的协议。OAuth 2.0 用于授权,OpenID Connect 用于认证。OpenID Connect 是 OAuth 2.0 协议之上的标识层,以使 OAuth 适用于认证的用例。
认证(Authentication)是确保通信实体是其所声称的实体。
授权(Authorization)是验证通信实体是否有权访问资源的过程。
换言之,认证关注的是你是谁,授权关注的是你有什么权限。
有两种 OAuth 2.0 授权流程最为常见:服务端应用程序的授权码流程和基于浏览器的应用程序的隐式流程。
OpenID Connect 是在 OAuth2.0 协议之上的标识层。它拓展了 OAuth2.0,使得认证方式标准化。
OAuth 不会立即提供用户身份,而是会提供用于授权的访问令牌。 OpenID Connect 使客户端能够通过认证来识别用户,其中,认证在授权服务端执行。它是这样实现的:在向授权服务端发起用户登录和授权告知的请求时,定义一个名叫openid的授权范围。在告知授权服务器需要使用 OpenID Connect 时,openid是必须存在的范围。
客户端发起的用于 OpenID Connect 认证请求 URI 会是如下的形式:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
client_id=your_client_id&
scope=openid%20contacts&
redirect_uri=https%3A//oauth2.example.com/code
该请求的返回结果是客户端可以用来交换访问令牌和 ID 令牌的授权码。如果 OAuth 流程是隐式的,那么授权服务端将直接返回访问令牌和 ID 令牌。
ID 令牌是 JWT,或者又称 JSON Web Token。JWT 是一个编码令牌,它由三部分组成:头部,有效负载和签名。在获得了 ID 令牌后,客户端可以将其解码,并且得到被编码在有效负载中的用户信息,如以下例子所示:
{
"iss": "https://accounts.google.com",
"sub": "10965150351106250715113082368",
"email": "johndoe@example.com",
"iat": 1516239022,
"exp": 1516242922
}
ID 令牌的有效负载包括了一些被称作声明的域。基本的声明有:
iss:令牌发布者
sub:用户的唯一标识符
email:用户的邮箱
iat:用 Unix 时间表示的令牌发布时间
exp:Unix 时间表示的令牌到期时间
然而,声明不仅限于上述这些域。由授权服务器对声明进行编码。客户端可以用这些信息来认证用户。
如果客户端需要更多的用户信息,客户端可以指定标准的 OpenID Connect 范围,来告知授权服务端将所需信息包括在 ID 令牌的有效负载中。这些范围包括个人主页(profile)、邮箱(email)、地址(address)和电话(phone)。
身份验证和授权交换通常涉及四方。 这些交换通常称为身份验证流。
身份验证流中的各方使用持有者令牌来确保、确认和验证某个主体(用户、主机或服务)并授予或拒绝对受保护资源的访问权限(授权)。 Microsoft 标识平台中的持有者令牌已格式化为 JSON Web 令牌 (JWT)。
标识平台使用三种类型的持有者令牌作为安全令牌:
客户端应用需要一种方法来信任 Microsoft 标识平台颁发给自己的安全令牌。 建立信任的第一步是注册应用。 当你注册应用时,标识平台会自动为其分配一些值,而其他值则由你根据应用程序的类型进行配置。
两个最常引用的应用注册设置为:
符合标准的实现提供身份验证和授权服务。 符合标准的授权服务器(例如标识平台)提供一组 HTTP 终结点,供身份验证流中的各方用于执行流。
当你注册或配置应用时,系统会自动生成应用的终结点 URI。 在应用的代码中使用的终结点取决于应用程序的类型以及应支持的标识(帐户类型)。
两个常用的终结点是授权终结点和令牌终结点。 下面是 authorize 和 token 终结点的示例:
# 1.授权终结点-由客户端用于从资源所有者获取授权
https://login.microsoftonline.com/<issuer>/oauth2/v2.0/authorize
# 2.令牌终结点-由客户端用于交换访问令牌的授权授予或刷新令牌
https://login.microsoftonline.com/<issuer>/oauth2/v2.0/token
命名空间:System.Security.Principal
//认证类型,如:微信、支付宝、验证码、jwt、windows等
AuthenticationType,
IsAuthenticated,//是否已经通过认证
Name //认证用户名称
IIdentity? Identity{get;}
//是否属于指定角色
bool IsInRole(string role);
var identity = new WindowsIdentity.GetCurrent();
IPrincipal principal = new WindowsPrincipal(identity);
//程序中就可以使用:
Thread.CurrentPrincipal = principal;
//或 如果是asp.net MVC 应用程序
HttpContext.User = principal;
var identity = new GenericIdentity("张三");
IPrincipal principal = new GenericPrincipal(identity,new[]{"admin","role2"});
3. 基于声明的 ClaimsIdentity (重要)
可以通过AddClaims(IEnumberable<Claim?>)方法自定义扩展内部信息
var identity = new CliamsIdentity("微信");
identity.AddClaim(new(ClaimTypes.Email,"root@qq.com"));
identity.AddClaim(new(ClaimTypes.Name,"张三"));
identity.AddClaim(new(ClaimTypes.Role,"Admin"));
identity.AddClaim(new(ClaimTypes.Role,"Users"));
//自定义增加需要的声明键值对
identity.AddClaim("TypeKey","TypeValue"));
IPrincipal principal = new GenericPrincipal(identity,new[]{"admin","role2"});
//判断当前用户是认证或说登录
bool isAuthenticated = principal.Identity.IsAuthenticated;
//判断当前用户是否拥有某角色
bool isInRole = principal.Identity.IsInRole("Admin");
核心包:Microsoft.Extensions.Identity.Core
仓储抽像包:Microsoft.Extensions.Identity.Stores
仓储EF实现包:Microsoft.AspNetCore.Identity.EntityFrameworkCore
官方UI实现包:Microsoft.AspNetCore.Identity.UI
builder.Services.AddMvc();builder.Services.AddIdentity<TUser,TRole>();builder.Services.AddIdentityCore<TUser>();builder.Services.AddDefaultIdentity<TUser>();builder.Services.AddDefaultIdentity<IdentityUser>(options=>
options.SignIn.RequireConfirmedAccount=true)
.AddEntityFrameworkStores<ApplicationsDbContext>();
builder.Service.AddRazorPages();
//授权中间件
app.UseAuthorization();
若需扩展则数据库上下文ApplicationsDbContext代码如下:
public class ApplicationsDbContext:IdentityDbContext<User,Role,string>
{
public ApplicationsDbContext(DbContextOptions options) : base(options)
{ }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<User>().ToTable("MyUsers");
}
}
生成的数据库表有:
AspNetRoleClaims
AspNetRoles
AspNetUserClaims
AspNetRoles
AspNetUsers
//后面这两张表是有关做微信、QQ等第三方登录即Auth2.0时用到的
AspNetUserLogins //相关第三方登录配置
AspNetUserTokens //相关第三方登录Token
Microstoft.AspNetCore.Components.Authorization@using Microstoft.AspNetCore.Components.Authorization@context?.User?.Identity 就是接口System.Security.Principal.IIdentitySystem.Security.Claims.ClaimsPrincipal.Identity再定义一个 AuthenticationStateProvider 的实现(它来自Microstoft.AspNetCore.Components.Authorization)
using Microstoft.AspNetCore.Components.Authorization;
namespace BlazorApp.Client.Pages;
public class MyAuthenticationStateProvider:AuthenticationStateProvider
{
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{//获得用户身份信息,并组装成AuthticationState类型返回
var identity = new ClaimsIdentity("custom",ClaimTypes.Name,ClaimTypes.Role);
identity.AddClaim(new(ClaimTypes.Name,"admin"));
return Task.FromResult(new AuthenticationState(new(identity)));
}
}
然后,在Program.cs文件中注册三个服务(如果是呈现模式是Auto,则需要在Server和Client端都注册该服务):
builder.Serivces.AddScoped<AuthenticationStateProvider,MyAuthenticationStateProvider>();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthrizationCore();
接下来是UI部分的实现
3.1 使用 AuthorizeView 组件做UI部分
<AuthorizeView>
<NotAuthorized>
<button>登录</button>
</NotAuthorized>
<Authorized>
@context?.User?.Identity?.Name
</Authorized>
</AuthorizeView>
3.2 不使用AuthorizeView 组件做UI
if(User is not null)
{
if(User.Identity.IsAuthenticated)
{
@User?.Identity?.Name
}
else
{
<button>登录</button>
}
}
@code
{
[CascadingParameter]Task<AuthenticationState> StateTask{get;set;}
ClaimsPrincipal? User{get;set;}
protected override asyncTask OnInitializedAsync()
{
User = (await StateTask).User;
}
}
3.3 使用 AuthorizeRouteView 组件,集成在Blazor的路由组件中完成验证
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@uouteData" DefaultLayout="@typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<p> 没有找到相关路由 </p>
</NotFound>
</Router>
把上面的路由视图组件 RouteView 改为 AuthorizeRouteView 即可变为在整个路由切换过程中要求每个终结点都必须经过认证验证。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。