IdentityServer4 是什么?
IdentityServer4 是基于 ASP.NET Core 实现的认证和授权框架, 是对 OpenID Connect 和 OAuth 2.0 协议的实现.
OpenID Connect 和 OAuth2.0 是什么
OpenID Connect:
OpenID Connect 由 OpenID 基金会于 2014 年发布的一个开放标准, 是建立在 OAuth 2.0 协议上的一个简单的身份标识层, OpenID Connect 兼容 OAuth 2.0. 实现身份认证(Authentication)
参考资料: https://openid.net/connect/
OpenID Connect 文档:
OAuth2.0:
OAuth2.0 是一个开放的工业标准的授权协议(Authorization), 它允许用户授权让第三方应用直接访问用户在某一个服务中的特定资源, 但不提供给第三方账号及密码信息
参考资料: https://www.cnblogs.com/xiandnc/p/9763121.html
OAuth2.0 文档: https://tools.ietf.org/html/rfc6749#page-73
Authentication 和 Authorization 的区别
authentication: n. 证明; 鉴定; 证实
authorization: n. 授权, 认可; 批准, 委任
前者是身份识别, 鉴别你是谁; 后者是授权许可, 告诉你可以做什么.
举个例子: 你吭哧吭哧写了一天的代码, 急于回家吃上一口媳妇做的热饭. 当你走到小区门口的时候你需要刷小区的门禁卡才能进入到小区里面, 然后再找到你家在哪一栋楼, 几单元几号, 然后掏出钥匙开门才能回到家. 在这个过程中刷小区的门禁就是认证你是这个小区的人, 拿你家的钥匙开门就是授权的过程, 如果你的认证不通过, 那就不存在授权.
OAuth2.0 的原理
我们先来了解一下 OAuth2.0 中的几个关键概念:
资源所有者(Resource Owner):
一个能够访问受保护资源的实体. 当资源所有者是一个人时, 它被称为终端用户
资源服务器(Resource Server):
托管受保护资源的服务器, 能够使用访问令牌接受和响应受保护的资源请求
客户端(Client):
代表资源所有者和其授权的应用程序来保护资源请求. 术语客户端并不意味着任何特定的实现特征(例如, 应用程序是否在服务器, 桌面或其他设备上执行)
授权服务器(Authorization Server):
在成功验证资源所有者并获得授权之后, 服务器向客户端发出访问令牌.(授权服务器是用来管理 Resource Owner,Resource Server,Client 的中间人)
场景: 小李想要打印 (美图快印) 自己三年来发布在新浪微博相册中和女朋友的照片, 有没有什么方法他既不告诉工作人员自己的新浪微博用账号和密码又能够方便快捷的把照片给到美图快印呢?(排除存 U 盘这种手工操作)
Authorization Server 和 Resource Server 可以使独立的服务提供商, 也可以是在一起的, 比如例子中新浪微博既作授权服务器也用来存储用户的图片资源. 我们可以看到 OAuth2 解决的问题是: 通过 Authorization Server 可以提供一个访问的凭据 (token) 给 client(美图快印的工作人员), 使得 client 可以在不知道 Resource Owner 以及 Resource Server 的用户名和密码的情况下访问到 Resource Owner 受保护的资源, 它是一个完美的中间人.
OAuth2.0 详细内容请参考: https://www.cnblogs.com/xiandnc/p/9763121.html
IdentityServer4 能做什么
用户认证服务
基于 OpenID Connect 实现的独立的认证服务实现对多平台 (web, native, mobile, services) 的集中认证
API 访问授权
为各种类型的客户机颁发 API 访问令牌, 例如服务器到服务器, Web 应用程序, spa 和 native/mobile 程序
联合身份认证
支持外部身份提供者, 如 Azure Active Directory,Google,Facebook 等
定制化的实现
IdentityServer4 的许多方面可以定制以满足您的需要, 因为它是一个框架, 而不是 SaaS 服务, 所以可以通过编写代码来调整实现, 以适应不同的场景
成熟的开原方案
使用许可的 Apache2 开源协议, 允许在其之上构建商业产品, 也作为. NET 基金会支持的项目 ()
提供免费的商业支持
官方可以对使用者提供部分的免费商业支持
IdentityServer4 定义的基本术语
IdentityServer
身份认证服务器是一个实现了 OpenID Connect 和 OAuth 2.0 协议的身份提供者, 它负责向客户端发布安全令牌
User
使用注册客户端访问资源的用户
Client
客户端从标识服务器请求令牌, 要么用于认证用户(请求身份令牌), 要么用于访问资源(请求访问令牌)
客户端必须首先在身份服务器上注册, 然后才能请求令牌
这里的客户端可以是 Web 应用程序, native mobile, desktop applications, SPA 等程序
Resource
资源是你想要用身份认证服务器保护的东西, 如: 用户的身份数据或 API
每个资源都有一个惟一的名称, 客户端使用这个名称来指定他们想要访问的资源
关于用户的身份数据标识(也称为 claim), 例如姓名或电子邮件地址
Identity Token
身份令牌代表身份验证过程的结果
Access Token
访问令牌授权客户端以允许访问哪些 API 资源, 访问令牌包含客户端和用户的信息
IdentityServer4 的简单示例
我们先来看一个简单的例子, 我们有三个 API ,Order, Product, Inventory, 我们利用 IdentityServer4 来实现对着三个 API 的认证和授权. 首先我们需要一个实现认证和授权的服务, 然后外部要想访问我们的 API 就必须通过统一的认证和授权服务的任何才可以, 否则就是返回 401: UnAuthorized , 未经授权的访问. 我们既可以将身份信息存储到内存中, 也可以将其持久化到数据库中, 此处我们使用内存模式快速的演示实现(示例代码中也支持存储到 DB 中, 使用 SqlLite + EF Core)
首先我们需要安装 IdentityServer4 的 Nuget 包, 然后在 ConfigureServices 方法中添加如下代码来初始化需要保护的 API 资源信息, 代码如下:
- public void ConfigureServices(IServiceCollection services)
- {
- // config data in memory
- services.AddIdentityServer()
- .AddDeveloperSigningCredential()
- .AddInMemoryApiResources(InitMemoryData.GetApiResources())
- .AddInMemoryClients(InitMemoryData.GetClients())
- .AddTestUsers(InitMemoryData.GetUsers());
- // config in DB
- //services.AddDbContext<IdentityServerDbContext>(options =>
- // options.UseSqlite(sqliteConnection));
- }
InitMemoryData 中的配置信息如下:
- // scopes define the API resources in your system
- public static IEnumerable<ApiResource> GetApiResources()
- {
- return new List<ApiResource>
- {
- new ApiResource("inventoryapi", "this is inventory api"),
- new ApiResource("orderapi", "this is order api"),
- new ApiResource("productapi", "this is product api")
- };
- }
- // clients want to access resources (aka scopes)
- public static IEnumerable<Client> GetClients()
- {
- // client credentials client
- return new List<Client>
- {
- new Client
- {
- ClientId = "inventory",
- AllowedGrantTypes = GrantTypes.ClientCredentials,
- ClientSecrets =
- {
- new Secret("inventorysecret".Sha256())
- },
- AllowedScopes = { "inventoryapi" }
- },
- new Client
- {
- ClientId = "order",
- AllowedGrantTypes = GrantTypes.ClientCredentials,
- ClientSecrets =
- {
- new Secret("ordersecret".Sha256())
- },
- AllowedScopes = { "orderapi" }
- },
- new Client
- {
- ClientId = "product",
- AllowedGrantTypes = GrantTypes.ClientCredentials,
- ClientSecrets =
- {
- new Secret("productsecret".Sha256())
- },
- AllowedScopes = { "productapi" }
- }
- };
- }
我们给 IdentityServer4 设置启动端口 5000, 认证服务的地址就是: http://localhost:5000/
然后认证 Server 端的代码就好了, 接下来我们需要在 API 添加授权服务的配置, 配置都很类似, 我们以 OrderAPI 为例:
- // This method gets called by the runtime. Use this method to add services to the container.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvcCore()
- .AddAuthorization()
- .AddJsonFormatters();
- services.AddAuthentication("Bearer")
- .AddIdentityServerAuthentication(options =>
- {
- options.Authority = "http://localhost:5000";
- options.RequireHttpsMetadata = false;
- options.ApiName = "orderapi";
- });
- }
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder App, IHostingEnvironment env)
- {
- App.UseAuthentication();
- App.UseMvc();
- }
这里我们配置的 Authority 地址就是认证授权的地址, AddAuthentication 中的 Bearer 是 Jwt Token 的一种, 具体可参考文章: https://www.cnblogs.com/Leo_wl/p/7792046.html
在 controller 中添加简单代码来返回 API 的信息:
- [Route("[controller]")]
- [Authorize]
- public class OrderController : ControllerBase
- {
- // GET API/order
- [HttpGet]
- public IActionResult Get()
- {
- var userIdentitys = from c in User.Claims
- select new UserIdentity
- {
- Type = c.Type,
- Value = c.Value
- };
- var result = new UserIdentityModel()
- {
- Description = "Access user order api successfully",
- UserIdentitys = userIdentitys.ToList()
- };
- return new JsonResult(result);
- }
- }
设置当前 API 的端口为: 5002
Product 和 Inventory 中的配置和这个类似, 端口信息以此设置为 5001,5003, 一切就绪, 让我们来测试一下结果:
启动 IdentotyServer, 以及三个 API, 我们使用 Postman 来请求 API, 下面站点就是 IdentityServer 的页面了:
接着我们来直接访问 OrderAPI 就会发现返回 401 , 这说明目前我们的 API 已经受保护了, 没有认证服务颁发的 token, 是直接访问不了的.
我们输入地址: http://localhost:5000/.well-known/openid-configuration 可以查看我们当前认证授权服务的配置信息:
现在还差一步就可以访问我们的 OrderAPI 了, 那就是: 客户端传入必要的信息给认证服务, 生成一定格式的 token, 然后携带着这个 token 来访问我们的服务
传入的三个参数分别是 grant_type , client_sercret, client_id 这几个参数分别代表了我们申请 token 时的授权方式是客户端授权, 密匙, clientid 信息. 我们在前面介绍过 IdentityServer4 是对 OAuth2.0 的实现, 所以具体参数的含义请参考之前 OAuth2.0 文章中的详细介绍
https://www.cnblogs.com/xiandnc/p/9763121.html
此时我们可以看到认证服务给我们返回了有效 token, 指定过去时间 3600s ,token 的类型是 Bearer, 然后我们再携带这这个 token 去访问服务试试看:
我们可以看到此时 API 返回了我们期待的正确结果, 如果在 1 小时后再携带着这个 token 去访问 API 就会提示 token 已过期, 需要重新生成才能够继续访问. 看完这个例子是不是很简单, 很清爽呢
例子参考代码: https://github.com/KenWang007/IdentityServer4Demo
来源: https://www.cnblogs.com/xiandnc/p/10150814.html