背景

国内来讲,注册/登录流程都是尽可能的简单,注册流程复杂,容易流失客户。手机号 + 短信验证码的方式非常普遍;但是框架默认并没有类似的功能,需要我们自己进行扩展。

思路

  1. 验证登录手机号为注册用户,且验证码正确;验证通过后,去 Identity Server 获取Token,然后返回客户端。
  2. 扩展 Identity 的授权方式,类似于 Authorization code;关于gtant type 可以参考 Grant Types — IdentityServer4 1.0.0 documentation (identityserver4test.readthedocs.io)

不过扩由于Identity Server 要收费,以及Abp 6.0 要集成 OpenIdDict;扩展 Grant Type 的方式,可以适用于当前,后续根据需要进行调整。

定义 GrantTypes

1  public class IdentityGrantTypes
2 {
3 public const string PhoneCode = "phone_code";
4 }
5

实现 IExtensionGrantValidator

主要实现对手机号以及短信验证码的校验

  1  public class PhoneCodeGrantValidator : IExtensionGrantValidator, ITransientDependency
2 {
3 private readonly IOptions<IdentityOptions> _identityOptions;
4 private readonly IAccountRepository _accountRepository;
5 private readonly IdentityUserManager _identityUserManager;
6 private readonly AccountTokenManager _accountTokenManager;
7
8 public string GrantType => IdentityGrantTypes.PhoneCode;
9
10 public PhoneCodeGrantValidator(
11 IOptions<IdentityOptions> identityOptions,
12 IAccountRepository accountRepository,
13 IdentityUserManager identityUserManager,
14 AccountTokenManager accountTokenManager)
15 {
16 _identityOptions = identityOptions;
17 _accountRepository = accountRepository;
18 _identityUserManager = identityUserManager;
19 _accountTokenManager = accountTokenManager;
20 }
21
22 public async Task ValidateAsync(ExtensionGrantValidationContext context)
23 {
24 await _identityOptions.SetAsync();
25
26 var phoneNumber = context.Request.Raw.Get("phoneNumber");
27 var code = context.Request.Raw.Get("code");
28
29 var validateParamsResult = ValidateRequestParams(phoneNumber, code);
30 if (!validateParamsResult.IsNullOrWhiteSpace())
31 {
32 SetContextError(validateParamsResult, context);
33 return;
34 }
35
36 var identityUser = await _accountRepository.FindByConfirmedPhoneAsync(phoneNumber);
37 if (identityUser == null)
38 {
39 SetContextError("无效的手机号", context);
40 return;
41 }
42
43 if (await _identityUserManager.IsLockedOutAsync(identityUser))
44 {
45 SetContextError("账户已锁定", context);
46 return;
47 }
48
49 var validateCodeResult = await ValidateCodeLoginAsync(phoneNumber, code);
50 if (!validateCodeResult.IsNullOrWhiteSpace())
51 {
52 await _identityUserManager.AccessFailedAsync(identityUser);
53 SetContextError(validateCodeResult, context);
54 return;
55 }
56
57 var claims = new List<Claim>
58 {
59 new("phoneNumber", phoneNumber)
60 };
61
62 if (identityUser.TenantId.HasValue)
63 {
64 claims.Add(new Claim(AbpClaimTypes.TenantId, identityUser.TenantId?.ToString()));
65 }
66
67 claims.AddRange(identityUser.Claims.Select(
68 item => new Claim(item.ClaimType, item.ClaimValue)));
69
70 context.Result = new GrantValidationResult(identityUser.Id.ToString(), GrantType, claims);
71 }
72
73 public async Task<string> ValidateCodeLoginAsync(string phoneNumber, string code)
74 {
75 var isValidCode = await _accountTokenManager.VerifySignInCodeAsync(phoneNumber, code);
76
77 return !isValidCode ? "无效的手机号或验证码" : string.Empty;
78 }
79
80 private static string ValidateRequestParams(
81 string phoneNumber, string code)
82 {
83 if (string.IsNullOrWhiteSpace(phoneNumber))
84 {
85 return "手机号不能为空";
86 }
87
88 if (string.IsNullOrWhiteSpace(code))
89 {
90 return "验证码不能为空";
91 }
92
93 return string.Empty;
94 }
95
96 private static void SetContextError(
97 string errorMessage, ExtensionGrantValidationContext context)
98 {
99 context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant)
100 {
101 ErrorDescription = errorMessage
102 };
103 }
104 }

注册扩展服务

1   public override void PreConfigureServices(ServiceConfigurationContext context)
2 {
3 PreConfigure<IIdentityServerBuilder>(builder =>
4 {
5 builder.AddExtensionGrantValidator<PhoneCodeGrantValidator>();
6 });
7 }

简单验证

至此,扩展方式的核心工作已经准备完成,可以通过 postman 进行简单的实验。

非扩展授权方式

此方式也比较简单,校验手机号以及验证码的主体逻辑一致,只需要验证用户之后,通过 httpClient 去 IdentityServer 获取token,然后返回客户端即可。

其他:为了更好的安全,在登录失败后需要显式的标记登录失败,配合 Identity 的一些策略,可以对一段时间内登录失败次数过多的账户,进行锁定,防止用户信息泄露。

结尾

近期已经从公司离职了。近期也思考了很多,大城市与二线城市在做事风格上确实差别比较大;也有很多令人唏嘘的事情,改天总结一下。

扩展.Net Core Identity Server 授权方式,实现 手机号+ 验证码 登录的更多相关文章

  1. ASP.NET Core Identity 实战(2)——注册、登录、Claim

    上一篇文章(ASP.NET Core Identity Hands On(1)--Identity 初次体验)中,我们初识了Identity,并且详细分析了AspNetUsers用户存储表,这篇我们将 ...

  2. .net core使用Ocelot+Identity Server统一网关验证

    源码下载地址:下载 项目结构如下图: 在Identity Server授权中,实现IResourceOwnerPasswordValidator接口: public class IdentityVal ...

  3. Asp.Net Core 中IdentityServer4 授权中心之自定义授权模式

    一.前言 上一篇我分享了一篇关于 Asp.Net Core 中IdentityServer4 授权中心之应用实战 的文章,其中有不少博友给我提了问题,其中有一个博友问我的一个场景,我给他解答的还不够完 ...

  4. Identity Server 4 原理和实战(完结)_建立Identity Server 4项目,Client Credentials 授权实例

    创建项目 dotnet new -i IdentityServer4.Templates 多出来的这些模板 adminUI用来测试,想要用再生产环境,需要交钱 结合core的 Identity来使用 ...

  5. 微服务系列之授权认证(二) identity server 4

    1.简介 IdentityServer4 是为ASP.NET Core系列量身打造的一款基于 OpenID Connect 和 OAuth 2.0 认证授权框架. 官方文档:https://ident ...

  6. 【.NET Core项目实战-统一认证平台】第十四章 授权篇-自定义授权方式

    [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我介绍了如何强制令牌过期的实现,相信大家对IdentityServer4的验证流程有了更深的了解,本篇我将介绍如何使用自定义的授权方 ...

  7. 第15章 使用EntityFramework Core进行配置和操作数据 - Identity Server 4 中文文档(v1.0.0)

    IdentityServer旨在实现可扩展性,其中一个可扩展点是用于IdentityServer所需数据的存储机制.本快速入门展示了如何配置IdentityServer以使用EntityFramewo ...

  8. Asp.net core Identity + identity server + angular 学习笔记 (第一篇)

    用了很长一段时间了, 但是一直没有做过任何笔记,感觉 identity 太多东西要写了, 提不起劲. 但是时间一久很多东西都记不清了. 还是写一轮吧. 加深记忆. 这是 0-1 的笔记, 会写好多篇. ...

  9. ASP.NET Core Identity 实战(4)授权过程

    这篇文章我们将一起来学习 Asp.Net Core 中的(注:这样描述不准确,稍后你会明白)授权过程 前情提要 在之前的文章里,我们有提到认证和授权是两个分开的过程,而且认证过程不属于Identity ...

随机推荐

  1. springboot+shiro 02 - 异步ajax请求无权限时,返回json格式数据

    博客: https://www.cnblogs.com/youxiu326/p/shiro-01.html github:https://github.com/youxiu326/sb_shiro_s ...

  2. C语言对源程序处理的四个步骤:预处理、编译、汇编、链接——预处理篇

    预处理 1)预处理的基本概念 C语言对源程序处理的四个步骤:预处理.编译.汇编.链接. 预处理是在程序源代码被编译之前,由预处理器(Preprocessor)对程序源代码进行的处理.这个过程并不对程序 ...

  3. html5系列:form 2.0 新结构

    以往的一个form表单,结构比较死板,所有的form元素都必须处在<form>和</form>之间才有效,这会造成一些麻烦,比如说:像bootstrap这种使用<div& ...

  4. 探索前端黑科技——通过 png 图的 rgba 值缓存数据

    本文系原创,欢迎转载,转载请注明作者信息项目地址:SphinxJS在线体验地址:https://jrainlau.github.io/sp... 说起前端缓存,大部分人想到的无非是几个常规的方案,比如 ...

  5. JAVA环境搭建之MyEclipse10+jdk1.8+tomcat8环境搭建详解

    一.安装JDK 1.下载得到jdk-8u11-windows-i586.1406279697.exe,直接双击运行安装,一直next就可以,默认是安装到系统盘下面Program Files, 我这里装 ...

  6. CSS简单样式练习(三)

    运行效果: 源代码: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta char ...

  7. FreeRTOS学习记录--任务创建函数详解

    开局一张图.一步一步分析就好. (一)什么是任务? 在多任务系统中,我们按照功能不同,把整个系统分割成一个个独立的,且无法返回的函数,这个函数我们称为任务:任务包含几个属性:任务堆栈,任务函数.任务控 ...

  8. 整合SSM框架环境搭建

    知识要求 MySQL相关操作 Maven操作 Mybatis.Spring.SpringMVC三个框架基本操作 JavaWeb等知识 搭建环境 MySQL 8.0 Mybatis 3.5.2 使用c3 ...

  9. 数据库纳管平台DBhouse的技术路线与实践

    为帮助开发者更好地了解和学习前沿数据库技术,腾讯云数据库特推出"DB · TALK"系列技术分享会,聚焦干货赋能创新,邀请数十位鹅厂资深数据库专家每月和您一起深入探讨云数据库的内核 ...

  10. Spring基于注解自动装配

    前面我们介绍Spring IoC装载的时候,使用XML配置这种方法来装配Bean,这种方法可以很直观的看到每个Bean的依赖,但缺点也很明显:写起来非常繁琐,每增加一个组件,就必须把新的Bean配置到 ...