0. 前言

通过前两篇我们实现了如何在Service层如何访问数据,以及如何运用简单的加密算法对数据加密。这一篇我们将探索如何实现asp.net core的身份验证。

1. 身份验证

asp.net core的身份验证有 JwtBearer和Cookie两种常见的模式,在这一篇我们将启用Cookie作为身份信息的保存。那么,我们如何启用呢?

在Startup.cs 的ConfigureServices(IServiceCollection services) 方法里添加如下:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
Configuration.Bind("CookieSettings",options);
});

此时可以启动一个权限验证,当用户访问需要验证的页面或接口时,如果没有登录,则会自动跳转到:

https://localhost:5001/Account/Login?ReturnUrl=XXXX

其中ReturnUrl指向来源页。

1.1 设置验证

当我们在Startup类里设置启用了身份验证后,并不是访问所有接口都会被跳转到登录页面。那么如何设置访问的路径需要身份验证呢?asp.net core为我们提供了一个特性类:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : Attribute, IAuthorizeData
{
public string Policy { get; set; }
public string Roles { get; set; }
public string AuthenticationSchemes { get; set; }
}

可以看的出,这个特性类允许设置在类、方法上,可以设置多个,允许子类继承父类的特性。所以可以在控制器上设置[Authorize],当在控制器上设置以后访问控制器里所有的Action都会要求验证身份;也可以单独设置在Action上,表示该Action需要验证身份,控制器里的其他方法不需要验证。

1.2 设置忽略

我们在开发过程中,会遇到这样的一组链接或者页面:请求地址同属于一个控制器下,但其中某个地址可以不用用户登录就可以访问。通常我们为了减少重复代码以及复用性等方面的考虑,会直接在控制器上设置身份验证要求,而不是在控制器里所有的Action上添加验证要求。

那么,我们如何放开其中的某个请求,可以允许它不用身份验证。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AllowAnonymousAttribute : Attribute, IAllowAnonymous
{
}

仔细观察,可以看得出这个特性可以设置在类、方法上,不允许多次设置,允许子类继承父类的特性。

这个特性的使用没啥可说的,不过需要注意的是,不要与AuthorizeAttribute一起使用。虽然编译上没啥问题,但实际上会对程序员的逻辑照成一定程度的误导。

2.保存身份

有身份验证,就必然需要保存身份。当我们从数据库中或者其他的三方服务中获取到用户信息后,我们需要将用户信息保存起来,而不是每次都向用户或者服务提供方索求信息。

在asp.net core中,Controller类里有一个属性:

public HttpContext HttpContext { get; }

HttpContext 提供了一个扩展方法,可以用来保存用户信息:

public static Task SignInAsync(this HttpContext context, ClaimsPrincipal principal);

暂时忽略这个方法的返回类型,它接受了一个ClaimsPrincipal类型的参数。我们来看下这个类的基本情况吧:

public class ClaimsPrincipal : IPrincipal
{ public ClaimsPrincipal();
public ClaimsPrincipal(IEnumerable<ClaimsIdentity> identities);
public ClaimsPrincipal(BinaryReader reader);
public ClaimsPrincipal(IIdentity identity);
public ClaimsPrincipal(IPrincipal principal); public static ClaimsPrincipal Current { get; }
public static Func<ClaimsPrincipal> ClaimsPrincipalSelector { get; set; }
public static Func<IEnumerable<ClaimsIdentity>, ClaimsIdentity> PrimaryIdentitySelector { get; set; }
public virtual IIdentity Identity { get; }
public virtual IEnumerable<ClaimsIdentity> Identities { get; }
public virtual IEnumerable<Claim> Claims { get; }
public virtual void AddIdentities(IEnumerable<ClaimsIdentity> identities);
public virtual void AddIdentity(ClaimsIdentity identity);
public virtual ClaimsPrincipal Clone();
public virtual IEnumerable<Claim> FindAll(Predicate<Claim> match);
public virtual IEnumerable<Claim> FindAll(string type);
public virtual Claim FindFirst(string type);
public virtual Claim FindFirst(Predicate<Claim> match);
public virtual bool HasClaim(Predicate<Claim> match);
public virtual bool HasClaim(string type, string value);
public virtual bool IsInRole(string role);
public virtual void WriteTo(BinaryWriter writer);
}

方法和属性有点多,那么我们重点关注一下构造函数以及可以AddXXX开头的方法。

这里有一个窍门,对于一个陌生的类来说,构造函数对于类本身是个很重要的特征,我们可以通过构造函数分析出这个类需要哪些基础数据。

所以,通过简单的分析,我们需要继续了解这两个类:

public class ClaimsIdentity : IIdentity
{
public ClaimsIdentity();
public ClaimsIdentity(string authenticationType);
public ClaimsIdentity(IIdentity identity);
public ClaimsIdentity(IEnumerable<Claim> claims);
public ClaimsIdentity(IEnumerable<Claim> claims, string authenticationType);
public ClaimsIdentity(IIdentity identity, IEnumerable<Claim> claims);
public ClaimsIdentity(string authenticationType, string nameType, string roleType);
public ClaimsIdentity(IEnumerable<Claim> claims, string authenticationType, string nameType, string roleType);
public ClaimsIdentity(IIdentity identity, IEnumerable<Claim> claims, string authenticationType, string nameType, string roleType); } public class Claim
{
public Claim(BinaryReader reader);
public Claim(BinaryReader reader, ClaimsIdentity subject); public Claim(string type, string value);
public Claim(string type, string value, string valueType);
public Claim(string type, string value, string valueType, string issuer); public Claim(string type, string value, string valueType, string issuer, string originalIssuer);
public Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject);
protected Claim(Claim other);
protected Claim(Claim other, ClaimsIdentity subject);
public string Type { get; }
public ClaimsIdentity Subject { get; }
public IDictionary<string, string> Properties { get; }
public string OriginalIssuer { get; }
public string Issuer { get; }
public string ValueType { get; }
public string Value { get; }
protected virtual byte[] CustomSerializationData { get; }
public virtual Claim Clone();
public virtual Claim Clone(ClaimsIdentity identity);
public override string ToString();
public virtual void WriteTo(BinaryWriter writer);
protected virtual void WriteTo(BinaryWriter writer, byte[] userData);
}

所以,看到这里就会发现,我们可以通过以下方式保存信息:

List<Claim> claims = null;
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme,new ClaimsPrincipal(identity));

这时候,数据就可以保存在Cookie里了,那么如何在控制器中获取到数据呢:

public ClaimsPrincipal User { get; }

在控制器中,提供了这样一个属性,当然如果想要正确获取到值的话,需要在 Startup.cs类中的添加如下配置:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ……省略其他配置
app.UseAuthorization();
app.UseAuthentication();
// ……省略其他配置
}

3. 总结

在这一篇中,简单介绍了asp.net core的identity,下一篇将从实际上带领大家设置不一样的identity以及Authorize验证。

更多内容烦请关注我的博客《高先生小屋》

【asp.net core 系列】13 Identity 身份验证入门的更多相关文章

  1. 坎坷路:ASP.NET Core 1.0 Identity 身份验证(中集)

    上一篇:<坎坷路:ASP.NET 5 Identity 身份验证(上集)> ASP.NET Core 1.0 什么鬼?它是 ASP.NET vNext,也是 ASP.NET 5,以后也可能 ...

  2. asp.net core系列 48 Identity 身份模型自定义

    一.概述 ASP.NET Core Identity提供了一个框架,用于管理和存储在 ASP.NET Core 应用中的用户帐户. Identity添加到项目时单个用户帐户选择作为身份验证机制. 默认 ...

  3. asp.net core系列 52 Identity 其它关注点

    一.登录分析 在使用identity身份验证登录时,在login中调用的方法是: var result = await _signInManager.PasswordSignInAsync(Input ...

  4. asp.net core系列 46 Identity介绍

    一. Identity 介绍 ASP.NET Core Identity是一个会员系统,可为ASP.NET Core应用程序添加登录功能.可以使用SQL Server数据库配置身份以存储用户名,密码和 ...

  5. ASP.NET Core系列:JWT身份认证

    1. JWT概述 JSON Web Token(JWT)是目前流行的跨域身份验证解决方案. JWT的官网地址:https://jwt.io JWT的实现方式是将用户信息存储在客户端,服务端不进行保存. ...

  6. asp.net core系列 49 Identity 授权(上)

    一.概述 授权是指用户能够访问资源的权限,如页面数据的查看.编辑.新增.删除.导出.下载等权限.ASP.NET Core 授权提供了多种且灵活的方式,包括:Razor pages授权约定.简单授权.R ...

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

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

  8. asp.net core中使用cookie身份验证

    配置 在 Startup.ConfigureServices 方法中,创建具有 AddAuthentication 和 AddCookie 方法的身份验证中间件服务: services.AddAuth ...

  9. asp.net core 3.1多种身份验证方案,cookie和jwt混合认证授权

    开发了一个公司内部系统,使用asp.net core 3.1.在开发用户认证授权使用的是简单的cookie认证方式,然后开发好了要写几个接口给其它系统调用数据.并且只是几个简单的接口不准备再重新部署一 ...

随机推荐

  1. 【C++】赋值过程中类型转换

    注意:以下内容摘自文献[1],修改了部分内容. 1.赋值过程中的类型转换 如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时自动进行类型转换. (1) 将浮点型数据(包括单.双精度)赋给 ...

  2. HttpSession之简易购物车

    创建一个简单的购物车模型,由三个 jsp 和两个 Servlet 组成: step1.jsp <%@ page language="java" contentType=&qu ...

  3. Sublime Text3 注册码(Windows/Build 3176版本)| 开发工具

    转自:dushusir.com 1.修改hosts文件(路径:C:\Windows\System32\drivers\etc): 0.0.0.0 www.sublimetext.com 0.0.0.0 ...

  4. 第六届蓝桥杯JavaB组国(决)赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.分机号 X老板脾气古怪,他们公司的电话分机号都是3位数,老板规定,所有号码必须是降序排列,且不能有重复的数位.比如: 751,520, ...

  5. Java实现 洛谷 P1601 A+B Problem(高精)

    import java.util.*; import java.math.*; public class Main { public static void main(String args[]) { ...

  6. Java实现三人年龄

    2 三人年龄 三个神秘蒙面人来访F博士. 博士询问他们年龄时,他们说:我们中年龄最小的不超过19岁.我们3人年龄总和为70岁.且我们三人年龄的乘积是所有可能情况中最大的. 请帮助F博士计算他们的年龄, ...

  7. kubernetes pod内抓包,telnet检查网络连接的几种方式

    背景 在日常kubernetes的运维中,经常遇到pod的网络问题,如pod间网络不通,或者端口不通,更复杂的,需要在容器里面抓包分析才能定位.而kubertnets的场景,pod使用的镜像一般都是尽 ...

  8. 剑指Offer之和为S的连续正数序列

    题目描述 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久,他 ...

  9. 记 Centos zabbix-agent启动失败解决思路

    一. 环境介绍 系统版本:Centos7.4 zabbix-agent 版本:zabbix-agent 3.4.7 二. 问题现象 启动zabbix-agent时启动失败 查看zabbix-agent ...

  10. linux安装redis-6.0.1单机和集群

    redis作为一个直接操作内存的key-value存储系统,也是一个支持数据持久化的Nosql数据库,具有非常快速的读写速度,可用于数据缓存.消息队列等. 一.单机版安装 1.下载redis 进入re ...