大家都知道我们的项目中已有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>

  1. Header:由algtyp组成,alg是algorithm的缩写,typ是type的缩写,指定token的类型。该部分使用Base64Url编码。
  2. Payload:主要用来存储信息,包含各种声明,同样该部分也由BaseURL编码。
  3. Signature:签名,使用服务器端的密钥进行签名。以确保Token未被篡改。

下一篇我们将介绍网关,通过网关来访问我们的用户模块的api资源,并集成IdentityServer4

NetCore项目实战篇04---集成IdentityService4的更多相关文章

  1. NetCore项目实战篇06---服务注册与发现之consul

    至此,我们的解决方案中新建了三个项目,网关(Zhengwei.Gateway).认证中心(Zhengwei.Identity)和用户资源API(Zhengwei.Use.Api).当要访问用户API的 ...

  2. NetCore项目实战篇08---Docker挂载mysql并连接.netCoreWeb

    我们的项目之前在直接连接的mysql,今天我们将通过docker挂载mysql 并与我们开发的webapi项目连接. 1. 安装docker 下载地址: https://download.docker ...

  3. NetCore项目实战篇05---添加Ocelot网关并集成identity server4认证

    今天来给我们的项目增加API网关,使用Ocelot. 它是系统暴露在外部的一个访问入口,这个有点像代理访问的家伙,就像一个公司的门卫承担着寻址.限制进入.安全检查.位置引导.等等功能.同时我们还要在网 ...

  4. NetCore项目实战篇02---全局异常处理

    在 .netcore中可以自定义自己的异常类型,步骤如下: 1.自定义自己的异常类型UserOperationException 并继承自Exception public class UserOper ...

  5. NetCore项目实战篇07---服务保护之polly

    1.  为什么要用polly 前面的项目中,一个服务调用另一个(Zhengwei.Identity调用Zhengwei.Use.Api)服务时是直接调用的,在这个调用的过程中可能会发生各种瞬态故障,这 ...

  6. NetCore项目实战篇03---HTTP Patch 更新数据

    一.什么是HTPP Patch HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 ...

  7. 洗礼灵魂,修炼python(82)--全栈项目实战篇(10)—— 信用卡+商城项目(模拟京东淘宝)

    本次项目相当于对python基础做总结,常用语法,数组类型,函数,文本操作等等 本项目在博客园里其他开发者也做过,我是稍作修改来的,大体没变的 项目需求: 信用卡+商城: A.信用卡(类似白条/花呗) ...

  8. C# Xamarin移动开发项目实战篇

    一.课程介绍 在前面阿笨的<C# Xamarin移动开发基础进修篇>课程中,大家已经熟悉和了解了Xamarin移动App开发的基础知识和原理.本次分享课<C# Xamarin移动开发 ...

  9. 洗礼灵魂,修炼python(73)--全栈项目实战篇(1)——【转载】前提准备之学习ubuntu

    本篇是为项目实战做准备,学习Linux是必备的,不然都不好意思叫全栈对吧?下面是一位资深大神写的文章,够详细,我也不用浪费时间再写了 原文链接:Ubuntu学习——第一篇 内容: 一. Ubuntu简 ...

随机推荐

  1. zathura-vim风格轻量级pdf阅读器

    安装(arch/manjaro) yay -Sy zathura-pdf-poppler 0.2.9-1 使用 `快捷键` gg 行首 G 行尾 j/k/h/l 单行移动 J/K 或 Ctrl + f ...

  2. unity3d之简单动画

    Unity3d中有两个关于动画的概念,Animation和Animator,看一下他们的创建和区别 1.创建一个物体后可以添加Animator和Animation组件如图所示 2.Animation和 ...

  3. Word文档创建目录

    一.以设置两级目录为例: 1.设置两个标题,标题1对应第一级目录,标题2对应第二级目录. 点击标题1,点击修改: 设置好样式和格式: 同理设置标题2. 2.创建多级目录: 选择级别1,关联到标题1,设 ...

  4. 用Python做一个知乎沙雕问题总结

    用Python做一个知乎沙雕问题总结 松鼠爱吃饼干2020-04-01 13:40 前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以 ...

  5. Hadoop权威指南(中文版-带目录索引)pdf电子书

      Hadoop权威指南(中文版-带目录索引)pdf电子书下载地址:百度网盘点击下载:链接:https://pan.baidu.com/s/1E-8eLaaqTCkKESNPDqq0jw 提取码:g6 ...

  6. mac 使用记录

    iterm 配合 lrzsz 实现 上传下载

  7. Redis分布式锁的正确姿势

    1. 核心代码: import redis.clients.jedis.Jedis; import java.util.Collections; /** * @Author: qijigui * @C ...

  8. pytorch 中word embedding 词向量的使用

  9. pytorch 中交叉熵损失实现方法

  10. Python自然语言处理实战核心技术与算法,Python自然语言处理,PyTorch深度学习实战【下载】

    本人买的,无私贡献给大家,无解压密码 下载地址: 链接:https://pan.baidu.com/s/1cJtnhEQSXHVMgygr8PHh9A 提取码:a54u