.NETCore微服务探寻(二) - 认证与授权
前言
一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目。正好由于最近刚好辞职,有了时间可以写写自己感兴趣的东西,所以在此想把自己了解的微服务相关的概念和技术框架使用实现记录在一个完整的工程中,由于本人技术有限,所以错误的地方希望大家指出。
目录
为什么需要认证授权服务
作为对外曝露的企业接口服务,当然不可能直接不需要任何的认证就可以随意访问接口,不然会面临巨大的安全隐患。由于单纯的认证和授权不需要与业务逻辑耦合并且访问频繁,所以可以单独划分为一个服务并根据具体业务做单独的服务优化(负载均衡等)
怎么创建认证与授权服务
.NETCore中除了官方的认证授权框架外,比较流行的是 IdentityServer4
什么是IdentityServer4
IdentityServer是用于ASP.NET Core 的免费,开源OpenID Connect和OAuth 2.0框架。IdentityServer4 由Dominick Baier和Brock Allen创建和维护,它整合了将基于令牌的身份验证,单点登录和API访问控制集成到您的应用程序中所需的所有协议实现和可扩展性点。IdentityServer4 已由OpenID Foundation正式认证,因此符合规范且可互操作。它是.NET Foundation的一部分,并根据其行为准则进行操作。它已获得Apache 2(OSI批准的许可证)的许可。
如何接入IdentityServer4
一、认证中心
新建 Auth Web项目作为认证中心
Auth项目 通过 Nuget 安装 IdentityServer
Auth项目 定义Api资源(ApiResource),身份资源(IdentityResource),客户端(Client)信息。
IdentityServer4可以通过持久化的方式定义这些信息,这里方便演示采用的是内存中定义
IdentityServerConfig.cs
using IdentityServer4.Models;
using System.Collections.Generic;
namespace ForDotNet.Auth.Config
{
/// <summary>
/// IdentityServer4配置信息
/// </summary>
public static class IdentityServerConfig
{
private const string AuthClientId = "Auth";
private const string Api1ClientId = "Api1";
/// <summary>
/// 获取api资源
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>()
{
new ApiResource("Auth","AuthApi"),
// new ApiResource("Api1","Api1"),
new ApiResource()
{
Name = "Api1",
DisplayName = "Api1Display",
Scopes = new Scope[]
{
new Scope("Api1","This Api1 Scope"),
new Scope ("Business","This is Business Scope"),
new Scope ("Admin","This Admin Scope")
}
}
};
}
/// <summary>
/// 获取客户端
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
Client authClient = new Client()
{
ClientId = AuthClientId,
ClientSecrets = new List<Secret>()
{
GetSecret(AuthClientId)
},
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes = new string[]
{
"Auth"
}
};
Client api1Client = new Client()
{
ClientId = Api1ClientId,
ClientSecrets = new List<Secret>()
{
GetSecret(Api1ClientId)
},
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes = new string[]
{
"Api1"
}
};
return new List<Client>()
{
authClient,
api1Client
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>()
{
new IdentityResources.OpenId()
};
}
#region 私有方法
/// <summary>
/// 获取Secret
/// </summary>
/// <param name="clientId">clientId</param>
/// <returns></returns>
private static Secret GetSecret(string clientId)
{
return new Secret(clientId.Sha256());
}
#endregion 私有方法
}
}
Startup.cs中注入这些服务
using ForDotNet.Auth.Config;
using ForDotNet.Common.Consul.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Collections.Generic;
namespace ForDotNet.Auth
{
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() // 注册IdentityServer4
.AddDeveloperSigningCredential() // 采用开发者凭证
.AddInMemoryApiResources(IdentityServerConfig.GetApiResources()) // 添加Api资源
.AddInMemoryClients(IdentityServerConfig.GetClients()) // 添加客户端
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources()) // 添加身份资源
.AddTestUsers(new List<IdentityServer4.Test.TestUser>() // 添加测试用户
{
new IdentityServer4.Test.TestUser ()
{
Username = "admin",
Password = "123",
SubjectId = "999"
}
});
// 注册服务发现服务
services.AddConsulServiceDiscovery();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime life)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// 注册IdentityServer
app.UseIdentityServer();
// 注册服务发现
app.UseConsulServiceDiscovery(life);
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
这里我们为了方便测试直接使用的是 AddTestUsers
添加的测试用户,如果我们需要自定义验证逻辑的话需要使用 AddResourceOwnerValidator<T>
,该方法接收一个实现了 IResourceOwnerPasswordValidator
接口的 T
类型。
定义一个 MyResourceOwnerValidator.cs
using IdentityServer4.Models;
using IdentityServer4.ResponseHandling;
using IdentityServer4.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace ForDotNet.Auth
{
/// <summary>
/// 我的校验逻辑
/// </summary>
public class MyResourceOwnerValidator : IResourceOwnerPasswordValidator
{
public MyResourceOwnerValidator()
{
// 可以注入服务
}
/// <summary>
/// 校验方法
/// </summary>
/// <param name="context">上下文信息(包含了用户名密码等信息)</param>
/// <returns></returns>
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
await Task.Run(()=>
{
//校验逻辑...
// 校验成功
if (DateTime.Now.Minute % 2 == 0)
{
context.Result = new GrantValidationResult(Guid.NewGuid().ToString(), "DIY",new List<Claim>()
{
new Claim ("DIYClaim","This is DIYClaim")
});
}
else
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "认证失败",
new Dictionary<string, object>()
{
{ "Test","This Is Test" }
});
}
});
}
}
}
如果使用了AddTestUsers的话则AddResourceOwnerValidator中实现的逻辑不会生效
public void ConfigureServices(IServiceCollection services)
{
services
.AddIdentityServer() // 注册IdentityServer4
.AddDeveloperSigningCredential() // 采用开发者凭证
.AddInMemoryApiResources(IdentityServerConfig.GetApiResources()) // 添加Api资源
.AddInMemoryClients(IdentityServerConfig.GetClients()) // 添加客户端
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources()) // 添加身份资源
.AddResourceOwnerValidator<MyResourceOwnerValidator>()
//.AddTestUsers(new List<IdentityServer4.Test.TestUser>() // 添加测试用户
//{
// new IdentityServer4.Test.TestUser ()
// {
// Username = "admin",
// Password = "123",
// SubjectId = "999"
// }
//});
// 注册服务发现服务
services.AddConsulServiceDiscovery();
services.AddControllers();
}
二、客户端(多个)
1.新建 Api 项目作为客户端
2.通过 Nuget安装 IdentityServer4.AccessTokenValidation
3.Api项目客户端 Startup.cs 中 注册认证
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ForDotNet.Common.Consul.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ForDotNet.Web.Api
{
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
.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5800"; // issuer地址
options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Both;
options.ApiName = "Api1";
options.RequireHttpsMetadata = false; // 启用http
});
services.AddConsulServiceDiscovery();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IHostApplicationLifetime life)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// 启用认证
app.UseAuthentication();
app.UseConsulServiceDiscovery(life);
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
三、运行并测试
1.客户端需要权限访问的接口添加 Authorize
特性
2.直接访问 http://localhost:5500/api/test
,响应401未授权
3.访问 http://localhost:5800/connect/token
请求token
由于我们的自定义逻辑 在当前时间分钟数 % 2 == 0 的时候 认证通过,反之失败
成功:
失败:
4.将获取到的token 添加到请求头中 访问 http://localhost:5500/api/test
200 响应请求成功
使用Ocelot 接入IdentityServer4
上面讲述的是没有使用网关的时候使用IdentityServer4,如果我们使用Ocelot的时候,下游服务运行在内网中与公网隔离时如何使用IdentityServer做统一的认证呢。
1.移除下游Api项目的认证代码
2.Ocelot添加认证配置
Startup中添加IdentityServer4认证配置信息
Ocelot.json配置文件中添加认证信息
AllowScopes
限制可以访问的范围 为空表示不限制
3.测试访问
直接通过网关访问 http://localhost:5000/api/v1/test
,响应401 未授权
通过 http://localhost:5000/auth/token
获取token ,访问 http://localhost:5000/api/v1/test
200 请求成功
尝试更改 AllowScopes
为 Business 再次访问,显示 403 禁止访问
将 AllowScopes
改为 Api1 再次访问,显示 200 请求成功
然后查看我们请求token所属客户端的 AllowScopes
为
与我们的限制范围 一致
.NETCore微服务探寻(二) - 认证与授权的更多相关文章
- .NETCore微服务探寻(三) - 分布式日志
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- .NETCore微服务探寻(三) - 远程过程调用(RPC)
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- .NETCore微服务探寻(一) - 网关
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- 7.【Spring Cloud Alibaba】微服务的用户认证与授权
有状态 vs 无状态 有状态 那么Session在何时创建呢? 当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中是通过调用HttpServ ...
- .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二)
原文:.NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二) 先上项目解决方案图: 以上可以看出项目结构可以划分为4大块,1是surging的核心底层,2,3,4都可以 ...
- (1)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- 什么是微服务架构,.netCore微服务选型
开发工具:VS2017 .Net Core 2.1 什么是微服务?单体结构: 缺点: 1)只能采用同一种技术,很难用不同的语言或者语言不同版本开发不同模块: 2)系统耦合性强,一旦其中一个模块有问题, ...
- (1).NET CORE微服务 Micro-Service ---- 什么是微服务架构,.netCore微服务选型
开发工具:VS2017 .Net Core 2.1 什么是微服务?单体结构: 缺点:1)只能采用同一种技术,很难用不同的语言或者语言不同版本开发不同模块:2)系统耦合性强,一旦其中一个模块有问题,整个 ...
- 什么是微服务架构,.netCore微服务选型
什么是微服务架构,.netCore微服务选型 https://www.cnblogs.com/uglyman/p/9182485.html 开发工具:VS2017 .Net Core 2.1 什么是微 ...
- .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---先让程序跑起来(一)
原文:.NetCore微服务Surging新手傻瓜式 入门教程 学习日志---先让程序跑起来(一) 写下此文章只为了记录Surging微服务学习过程,并且分享给广大想学习surging的基友,方便广大 ...
随机推荐
- 技术大佬:我去,这个容易被忽略的小程序Image图片属性,竟然这么屌!
前段时间在做“高清壁纸推荐”小程序优化的时候,发现一个很实用的图片属性——能够实现最大化压缩图片大小.且图片质量最小的损失,在此之前一直没有注意.今天跟大家分享一下这个属性的用法,主要是让大家能够,意 ...
- 看了这篇,我确定你已经彻底搞懂Java的继承了
遇到认真的读者是作者的一种幸运,真的,上一篇接口推送后,有好几个读者留言说,"二哥,你有一处内容需要修正,应该是接口中不能有 private 和 protected 修饰的方法." ...
- IT笑话十则(一)
一.下班前发给你 客户:“这个图下班之前必须发给我!” 设计师:“好的!” 第二天清早. 客户:“图怎么还没发过来?” 设计师:“我还没下班呢…” 二.受伤的老三 行业老大与老二PK,受伤的并非对 ...
- Active MQ未授权访问
ActiveMQ是一款流行的开源消息服务器.默认情况下,ActiveMQ服务是没有配置安全参数.恶意人员可以利用默认配置弱点发动远程命令执行攻击,获取服务器权限,从而导致数据泄露. 一.未授权访问 默 ...
- 01 . Squid原理配置和使用
Squid简介 Squid是一个支持HTTP,HTTPS,FTP等服务的Web缓存代理软件,它可以通过缓存页面来提高服务器的相应速度并降低带宽占用.并且,Squid还具有强大的访问控制功能.Squid ...
- 实验三 UML 建模工具的安装与使用
UML 建模工具的安装与使用一. 实验目的1) 学习使用 EA(Enterprise Architect) 开发环境创建模型的一般方法: 2) 理解 EA 界面布局和元素操作的一般技巧: 3) 熟悉 ...
- 副业收入是我做程序媛的3倍,工作外的B面人生
到“程序员”,多数人脑海里首先想到的大约是:为人木讷.薪水超高.工作枯燥…… 然而,当离开工作岗位,撕去层层标签,脱下“程序员”这身外套,有的人生动又有趣,马上展现出了完全不同的A/B面人生! 不论是 ...
- Beta冲刺 ——5.27
这个作业属于哪个课程 软件工程 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.组员一起学习Git分支管 ...
- jchdl - RTL实例 - MOS6502 ALU (Verilog)
https://mp.weixin.qq.com/s/jLUz757FQZjMEYzYb2AIww MOS6502是简单,但是曾经相当流行的一款CPU.网上有很多模拟程序可供学习使用.这里使用一个 ...
- Java实现 LeetCode 816 模糊坐标(暴力)
816. 模糊坐标 我们有一些二维坐标,如 "(1, 3)" 或 "(2, 0.5)",然后我们移除所有逗号,小数点和空格,得到一个字符串S.返回所有可能的原始 ...