NetCore项目实战篇04---集成IdentityService4
大家都知道我们的项目中已有web api,现在可以正式访问,不论任何人只要通过输入对应的api网址就可以访问到我们的api 资源,这样是很不安全的,我们需求对当前用户进行身份验证,因此我们在项目中使用IdentityServer4来对受保护资源并实现身份验证和/或授权,直接开始上代码,这些代码直接可以在你的项目中使用,并跑起来。
1、 新建一个空的.netcore web项目,并引入IdentityService4的NuGet包。
2、 在项目中增加一个config.cs文件
public class Config
{
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId="iphone",
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
RefreshTokenExpiration = TokenExpiration.Sliding,
AllowOfflineAccess = true,
RequireClientSecret = false,
AllowedGrantTypes = new List<string>{"sms_suth_code"},
AlwaysIncludeUserClaimsInIdToken = true,
AllowedScopes = new List<string>
{
"gateway_api",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
}, },
new Client
{
ClientId="android",
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
RefreshTokenExpiration = TokenExpiration.Sliding,
AllowOfflineAccess = true,
RequireClientSecret = false,
AllowedGrantTypes = new List<string>{"sms_auth_code"},
AlwaysIncludeUserClaimsInIdToken = true,
AllowedScopes = new List<string>
{
"gateway_api",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
}, }
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("gateway_api","user service")
};
} }
3、在项目中新增类SmsAuthCodeValidator该类主要是实现IdentityServer4组件中的IextensionGrantValidator接口ValidateAsync()的方法,在该方法写上自己的验证逻辑,这里我们只用户在登录时输入的手机号和验证码进行了校验,当然在校验时会调用用户模块的api,也就是我们_userService.CheckOrCreate(phone)方法,服务之前如何发现和调用这里不展开,下节介绍。SmsAuthCodeValidator代码如下
public class SmsAuthCodeValidator : IExtensionGrantValidator
{
private readonly IAuthCodeService _authCodeService;
private readonly IUserService _userService;
public SmsAuthCodeValidator(IAuthCodeService authCodeService, IUserService userService)
{
_authCodeService = authCodeService;
_userService = userService;
}
public string GrantType => "sms_auth_code"; public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var phone = context.Request.Raw["phone"];
var code = context.Request.Raw["auth_code"];
var error = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
if(!string.IsNullOrEmpty(phone)&& !string.IsNullOrEmpty(code))
{
//用户检查
_authCodeService.Validate(phone, code);
//用户注册
var userId = await _userService.CheckOrCreate(phone);
if(userId <=)
{
context.Result = error;
return;
} context.Result = new GrantValidationResult(userId.ToString(), GrantType);
}
else
{
context.Result = error; } }
}
4、在SmsAuthCodeValidator类我们引用了两个本地的服务,一个是对验证码进行校验的AuthCodeService类,一个是对手机号进行校验的UserService,也就是在这个类中对用户服务模块进行的手机号校验。现将这两个代码的代码写上
public interface IAuthCodeService
{
/// <summary>
/// 验证
/// </summary>
/// <param name="phone">手机号</param>
/// <param name="authCone">验证码</param>
/// <returns></returns>
bool Validate(string phone, string authCone);
} public class AuthCodeService : IAuthCodeService
{
public bool Validate(string phone, string authCone)
{
return true;
}
}
public interface IUserService
{
/// <summary>
/// 检查手机是否注册,如果没有就创建
/// </summary>
/// <param name="phone"></param>
Task<int> CheckOrCreate(string phone);
} public class UserService : IUserService
{ public async Task<int> CheckOrCreate(string phone)
{ return ; }
}
5、最后我们需要增加IdentityServer4中间件,并对我们的服务进行配置
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddExtensionGrantValidator<SmsAuthCodeValidator>()
.AddDeveloperSigningCredential()
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources());
services.AddSingleton(new HttpClient());
services.AddScoped<IAuthCodeService, AuthCodeService>()
.AddScoped<IUserService, UserService>(); services.AddMvc();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
app.UseMvc();
}
}
5、 生成并启动该项目,通过postman访问,需求增加如下六个参数
6、如果没有问题的话我们会获取到系统反馈给我们的token值,返回结果如下:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjlhMjJlN2E3Zjg1ZmY5MjNiMTJmM2Nm
NGZkMGM3YzYzIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1ODg5MjE2MjUsImV4cCI6
MTU4ODkyNTIyNSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDoxMTEwIiwiYXVkIjpb
Imh0dHA6Ly9sb2NhbGhvc3Q6MTExMC9yZXNvdXJjZXMiLCJnYXRld2F5X2FwaSJd
LCJjbGllbnRfaWQiOiJhbmRyb2lkIiwic3ViIjoiMyIsImF1dGhfdGltZSI6MTU4
ODkyMTYyNSwiaWRwIjoibG9jYWwiLCJzY29wZSI6WyJvcGVua
WQiLCJwcm9maWxlIiwiZ2F0ZXdheV9hcGkiLCJvZmZsaW5lX2FjY2VzcyJdLCJhb
XIiOlsic21zX2F1dGhfY29kZSJdfQ.pyEKOe08jiqtg1rgcf0UGO0hmfEhI5a2cIXw
_-YgXdLVceKa14Jhyy8Ezgom3ipNlci5FwmN-p5ro_3ORtzreU0qxhiCzI5kyPgLRP
lOO8cFykYKY4yQOCD_z2LohSxyvAsTPn0B75_iodujGPQAB4Outs9uAjcHXAnxjBkn
DKl6L5uu609ZaugG4X6T2xx0ZDU-VftrrmB-YX5oe6FU70R4jsRLayL8nrM-u-Q_We
UIfY04M91REX9HqneOGyxSDj2Qku22pC68dlIYQNGhBlYUnSqRMkk39Pe9UmjO8dSp
qqBMtHBEwCQn3cMzG7UbP5gB6F2GgTICUBERbxxwRA",
"expires_in": ,
"token_type": "Bearer",
"refresh_token": "f3051fa24cebf7cbfa73b55563a283bb3c15b129c8c5ff732324a653a7c6eff1"
}
7、 怀着好奇的心我们来看看这个access_token的值反馈给我们的是什么,其实他就是JWT(Json Web Token),解析成json格式如下
{
alg: "RS256", kid: "9a22e7a7f85ff923b12f3cf4fd0c7c63", typ: "JWT" }.
{
nbf: , exp: , iss: "http://localhost:1110", aud: [
"http://localhost:1110/resources", "gateway_api" ], client_id: "android", sub: "", auth_time: , idp: "local", scope: [
"openid", "profile", "gateway_api", "offline_access" ], amr: [
"sms_auth_code" ] }.
[signature]
顺便学习一下JWT吧:
HTTP提供了一套标准的身份验证框架:服务器可以用来针对客户端的请求发送质询(challenge),客户端根据质询提供身份验证凭证。质询与应答的工作流程如下:服务器端向客户端返回401(Unauthorized,未授权)状态码,并在WWW-Authenticate头中添加如何进行验证的信息,其中至少包含有一种质询方式。然后客户端可以在请求中添加Authorization头进行验证,其Value为身份验证的凭证信息。
Bearer认证(也叫做令牌认证)是一种HTTP认证方案,其中包含的安全令牌的叫做Bearer Token。因此Bearer认证的核心是Token。那如何确保Token的安全是重中之重。一种方式是使用Https,另一种方式就是对Token进行加密签名。而JWT就是一种比较流行的Token编码方式。可以看出JWT有三部分组成:
<header>.<payload>.<signature>
- Header:由
alg
和typ
组成,alg
是algorithm的缩写,typ
是type的缩写,指定token的类型。该部分使用Base64Url
编码。 - Payload:主要用来存储信息,包含各种声明,同样该部分也由
BaseURL
编码。 - Signature:签名,使用服务器端的密钥进行签名。以确保Token未被篡改。
下一篇我们将介绍网关,通过网关来访问我们的用户模块的api资源,并集成IdentityServer4
NetCore项目实战篇04---集成IdentityService4的更多相关文章
- NetCore项目实战篇06---服务注册与发现之consul
至此,我们的解决方案中新建了三个项目,网关(Zhengwei.Gateway).认证中心(Zhengwei.Identity)和用户资源API(Zhengwei.Use.Api).当要访问用户API的 ...
- NetCore项目实战篇08---Docker挂载mysql并连接.netCoreWeb
我们的项目之前在直接连接的mysql,今天我们将通过docker挂载mysql 并与我们开发的webapi项目连接. 1. 安装docker 下载地址: https://download.docker ...
- NetCore项目实战篇05---添加Ocelot网关并集成identity server4认证
今天来给我们的项目增加API网关,使用Ocelot. 它是系统暴露在外部的一个访问入口,这个有点像代理访问的家伙,就像一个公司的门卫承担着寻址.限制进入.安全检查.位置引导.等等功能.同时我们还要在网 ...
- NetCore项目实战篇02---全局异常处理
在 .netcore中可以自定义自己的异常类型,步骤如下: 1.自定义自己的异常类型UserOperationException 并继承自Exception public class UserOper ...
- NetCore项目实战篇07---服务保护之polly
1. 为什么要用polly 前面的项目中,一个服务调用另一个(Zhengwei.Identity调用Zhengwei.Use.Api)服务时是直接调用的,在这个调用的过程中可能会发生各种瞬态故障,这 ...
- NetCore项目实战篇03---HTTP Patch 更新数据
一.什么是HTPP Patch HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 ...
- 洗礼灵魂,修炼python(82)--全栈项目实战篇(10)—— 信用卡+商城项目(模拟京东淘宝)
本次项目相当于对python基础做总结,常用语法,数组类型,函数,文本操作等等 本项目在博客园里其他开发者也做过,我是稍作修改来的,大体没变的 项目需求: 信用卡+商城: A.信用卡(类似白条/花呗) ...
- C# Xamarin移动开发项目实战篇
一.课程介绍 在前面阿笨的<C# Xamarin移动开发基础进修篇>课程中,大家已经熟悉和了解了Xamarin移动App开发的基础知识和原理.本次分享课<C# Xamarin移动开发 ...
- 洗礼灵魂,修炼python(73)--全栈项目实战篇(1)——【转载】前提准备之学习ubuntu
本篇是为项目实战做准备,学习Linux是必备的,不然都不好意思叫全栈对吧?下面是一位资深大神写的文章,够详细,我也不用浪费时间再写了 原文链接:Ubuntu学习——第一篇 内容: 一. Ubuntu简 ...
随机推荐
- 让ul li水平居中(任意删除li也能水平居中)
HTML代码: <div class="box"> <ul class="button-ct"> <li></li&g ...
- 【three.js第三课】鼠标事件,移动、旋转物体
1.下载three.js的源码包后,文件夹结构如下: 2.在[three.js第一课]的代码基础上,引入OrbitControls.js文件,此文件主要用于 对鼠标的操作. 该文件位置:在文件结构中 ...
- Python-气象-大气科学-可视化绘图系列(一)——利用xarray读取netCDF文件并画图(代码+示例)
本文原创链接:https:////www.cnblogs.com/zhanling/p/12192978.html 1 import numpy as np import xarray as xr i ...
- php7.2.1+redis3.2.1 安装redis扩展(windows系统)
前提:已成功安装PHP环境和Redis服务 下面进入正题: 第一步,下载redis驱动扩展文件,注意:需要根据上面信息下载对应版本 https://windows.php.net/downloads/ ...
- LeetCode#160-Intersection of Two Linked Lists-相交链表
一.题目 编写一个程序,找到两个单链表相交的起始节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, listA = [4,1,8,4,5], l ...
- 详解 File类
在讲解File类之前,本人先要讲解下 路径,因为我们对于文件的操作是离不开路径的: 目录 路径: File类 文件名称过滤器: 路径: 请观看本人博文 -- <详解 绝对路径与 相对路径> ...
- vue-cli目录结构分析
vue3初始化一个项目,查看其项目结构,会发现比vue2的更加简洁. package.json说明 项目的配置文件,定义了项目的基本信息以及项目的相关包依赖,npm运行命令等,位于项目根目录. scr ...
- 使用 selenium 实现谷歌以图搜图爬虫
使用selenium实现谷歌以图搜图 实现思路 原理非常简单,就是利用selenium去操作浏览器,获取到想要的链接,然后进行图片的下载,和一般的爬虫无异. 用到的技术:multiprocessing ...
- [V&N2020 公开赛] Web misc部分题解
0x00 前言 写了一天题目,学到了好多东西, 简单记录一下 0x01 Web HappyCTFd 直接使用网上公开的cve打: 解题思路:先注册一个admin空格账号,注意这里的靶机无法访问外网,邮 ...
- srt字幕翻译
需要把字幕名改成i.txt 有有道和谷歌 代码: #Author:Chenglong Qian #Copyright :Chenglong Qian import json import reques ...