Ocelot(四)- 认证与授权

作者:markjiang7m2

原文地址:https://www.cnblogs.com/markjiang7m2/p/10932805.html

源码地址:https://gitee.com/Sevenm2/OcelotDemo

本文是我关于Ocelot系列文章的第四篇,认证与授权。在前面的系列文章中,我们的下游服务接口都是公开的,没有经过任何的认证,只要知道接口的调用方法,任何人都可以随意调用,因此,很容易就造成信息泄露或者服务被攻击。

正如,我要找Willing干活之前,我得先到HR部门那里登记并且拿到属于我自己的工卡,然后我带着我的工卡去找Willing,亮出我是公司员工的身份,并且有权利要求他帮我完成一个任务。

在这里集成一套 .net core的服务认证框架IdentityServer4,以及如何在Ocelot中接入IdentityServer4的认证与授权。

跟上一篇Ocelot(三)- 服务发现文章中的Consul类似,这一个是关于Ocelot的系列文章,我暂时也不打算详细展开说明IdentityServer4,在本文中也是使用IdentityServer4最简单的Client认证模式。

关于更多的Ocelot功能介绍,可以查看我的系列文章

本文中涉及案例的完整代码都可以从我的代码仓库进行下载。

IdentityServer4使用

IdentityServer4有多种认证模式,包括用户密码、客户端等等,我这里只需要实现IdentityServer4的验证过程即可,因此,我选择了使用最简单的客户端模式。

首先我们来看,当没有Ocelot网关时系统是如何使用IdentityServer4进行认证的。

客户端需要先想IdentityServer请求认证,获得一个Token,然后再带着这个Token向下游服务发出请求。

我尝试根据流程图搭建出这样的认证服务。

创建IdentityServer服务端

新建一个空的Asp.Net Core Web API项目,因为这个项目只做IdentityServer服务端,因此,我将Controller也直接删除掉。

使用NuGet添加IdentityServer4,可以直接使用NuGet包管理器搜索IdentityServer4进行安装,或者通过VS中内置的PowerShell执行下面的命令行

  1. Install-Package IdentityServer4

appsettings.json中添加IdentityServer4的配置

  1. {
  2. "Logging": {
  3. "LogLevel": {
  4. "Default": "Warning"
  5. }
  6. },
  7. "SSOConfig": {
  8. "ApiResources": [
  9. {
  10. "Name": "identityAPIService",
  11. "DisplayName": "identityAPIServiceName"
  12. }
  13. ],
  14. "Clients": [
  15. {
  16. "ClientId": "mark",
  17. "ClientSecrets": [ "markjiang7m2" ],
  18. "AllowedGrantTypes": "ClientCredentials",
  19. "AllowedScopes": [ "identityAPIService" ]
  20. }
  21. ]
  22. },
  23. "AllowedHosts": "*"
  24. }

ApiResources为数组类型,表示IdentityServer管理的所有的下游服务列表

  • Name: 下游服务名称
  • DisplayName: 下游服务别名

Clients为数组类型,表示IdentityServer管理的所有的上游客户端列表

  • ClientId: 客户端ID
  • ClientSecrets: 客户端对应的密钥
  • AllowedGrantTypes: 该客户端支持的认证模式,目前支持如下:
    • Implicit
    • ImplicitAndClientCredentials
    • Code
    • CodeAndClientCredentials
    • Hybrid
    • HybridAndClientCredentials
    • ClientCredentials
    • ResourceOwnerPassword
    • ResourceOwnerPasswordAndClientCredentials
    • DeviceFlow
  • AllowedScopes: 该客户端支持访问的下游服务列表,必须是在ApiResources列表中登记的

新建一个类用于读取IdentityServer4的配置

  1. using IdentityServer4.Models;
  2. using Microsoft.Extensions.Configuration;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. namespace IdentityServer
  8. {
  9. public class SSOConfig
  10. {
  11. public static IEnumerable<ApiResource> GetApiResources(IConfigurationSection section)
  12. {
  13. List<ApiResource> resource = new List<ApiResource>();
  14. if (section != null)
  15. {
  16. List<ApiConfig> configs = new List<ApiConfig>();
  17. section.Bind("ApiResources", configs);
  18. foreach (var config in configs)
  19. {
  20. resource.Add(new ApiResource(config.Name, config.DisplayName));
  21. }
  22. }
  23. return resource.ToArray();
  24. }
  25. /// <summary>
  26. /// 定义受信任的客户端 Client
  27. /// </summary>
  28. /// <returns></returns>
  29. public static IEnumerable<Client> GetClients(IConfigurationSection section)
  30. {
  31. List<Client> clients = new List<Client>();
  32. if (section != null)
  33. {
  34. List<ClientConfig> configs = new List<ClientConfig>();
  35. section.Bind("Clients", configs);
  36. foreach (var config in configs)
  37. {
  38. Client client = new Client();
  39. client.ClientId = config.ClientId;
  40. List<Secret> clientSecrets = new List<Secret>();
  41. foreach (var secret in config.ClientSecrets)
  42. {
  43. clientSecrets.Add(new Secret(secret.Sha256()));
  44. }
  45. client.ClientSecrets = clientSecrets.ToArray();
  46. GrantTypes grantTypes = new GrantTypes();
  47. var allowedGrantTypes = grantTypes.GetType().GetProperty(config.AllowedGrantTypes);
  48. client.AllowedGrantTypes = allowedGrantTypes == null ?
  49. GrantTypes.ClientCredentials : (ICollection<string>)allowedGrantTypes.GetValue(grantTypes, null);
  50. client.AllowedScopes = config.AllowedScopes.ToArray();
  51. clients.Add(client);
  52. }
  53. }
  54. return clients.ToArray();
  55. }
  56. }
  57. public class ApiConfig
  58. {
  59. public string Name { get; set; }
  60. public string DisplayName { get; set; }
  61. }
  62. public class ClientConfig
  63. {
  64. public string ClientId { get; set; }
  65. public List<string> ClientSecrets { get; set; }
  66. public string AllowedGrantTypes { get; set; }
  67. public List<string> AllowedScopes { get; set; }
  68. }
  69. }

Startup.cs中注入IdentityServer服务

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. var section = Configuration.GetSection("SSOConfig");
  4. services.AddIdentityServer()
  5. .AddDeveloperSigningCredential()
  6. .AddInMemoryApiResources(SSOConfig.GetApiResources(section))
  7. .AddInMemoryClients(SSOConfig.GetClients(section));
  8. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  9. }

使用IdentityServer中间件

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  2. {
  3. if (env.IsDevelopment())
  4. {
  5. app.UseDeveloperExceptionPage();
  6. }
  7. app.UseIdentityServer();
  8. app.UseMvc();
  9. }

配置完成,接下来用Debug模式看看IdentityServer是否可用,尝试向IdentityServer进行认证。因为需要使用post方式,而且在认证请求的body中加入认证信息,所以我这里借助Postman工具完成。

请求路径:<host>+/connect/token

如果认证正确,会得到如下结果:

如果认证失败,则会返回如下:

这样,最简单的IdentityServer服务就配置完成了。当然,我刚刚为了快速验证IdentityServer服务是否搭建成功,所以使用的是Debug模式,接下来要使用的话,还是要通过IIS部署使用的,我这里就把IdentityServer服务部署到8005端口。

下游服务加入认证

OcelotDownAPI项目中,使用NuGet添加AccessTokenValidation包,可以直接使用NuGet包管理器搜索IdentityServer4.AccessTokenValidation进行安装,或者通过VS中内置的PowerShell执行下面的命令行

  1. Install-Package IdentityServer4.AccessTokenValidation

appsettings.json中加入IdentityServer服务信息

  1. "IdentityServerConfig": {
  2. "ServerIP": "localhost",
  3. "ServerPort": 8005,
  4. "IdentityScheme": "Bearer",
  5. "ResourceName": "identityAPIService"
  6. }

这里的identityAPIService就是在IdentityServer服务端配置ApiResources列表中登记的其中一个下游服务。

Startup.cs中读取IdentityServer服务信息,加入IdentityServer验证

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. IdentityServerConfig identityServerConfig = new IdentityServerConfig();
  4. Configuration.Bind("IdentityServerConfig", identityServerConfig);
  5. services.AddAuthentication(identityServerConfig.IdentityScheme)
  6. .AddIdentityServerAuthentication(options =>
  7. {
  8. options.RequireHttpsMetadata = false;
  9. options.Authority = $"http://{identityServerConfig.IP}:{identityServerConfig.Port}";
  10. options.ApiName = identityServerConfig.ResourceName;
  11. }
  12. );
  13. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  14. }
  15. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  16. {
  17. if (env.IsDevelopment())
  18. {
  19. app.UseDeveloperExceptionPage();
  20. }
  21. app.UseAuthentication();
  22. app.UseMvc();
  23. }

根据前面的配置,我们添加一个需要授权的下游服务API

注意添加属性[Authorize]

因为我这里只是为了演示IdentityServer的认证流程,所以我只是在其中一个API接口中添加该属性,如果还有其他接口需要整个认证,就需要在其他接口中添加该属性,如果是这个Controller所有的接口都需要IdentityServer认证,那就直接在类名前添加该属性。

  1. using Microsoft.AspNetCore.Authorization;
  1. // GET api/ocelot/identityWilling
  2. [HttpGet("identityWilling")]
  3. [Authorize]
  4. public async Task<IActionResult> IdentityWilling(int id)
  5. {
  6. var result = await Task.Run(() =>
  7. {
  8. ResponseResult response = new ResponseResult()
  9. { Comment = $"我是Willing,既然你是我公司员工,那我就帮你干活吧, host: {HttpContext.Request.Host.Value}, path: {HttpContext.Request.Path}" };
  10. return response;
  11. });
  12. return Ok(result);
  13. }

重新打包OcelotDownAPI项目,并发布到8001端口。

首先,像之前那样直接请求API,得到如下结果:

得到了401的状态码,即未经授权。

因此,我必须先向IdentityServer请求认证并授权

然后将得到的TokenBearer的方式加入到向下游服务的请求当中,这样我们就可以得到了正确的结果

可能有些朋友在这里会有点疑惑,在Postman中我们在Authorization中加入这个Token,但是在我们实际调用中该怎么加入Token?

其实熟悉Postman的朋友可能就知道怎么一回事,Postman为了我们在使用过程中更加方便填入Token信息而单独列出了Authorization,实际上,最终还是会转换加入到请求头当中

这个请求头的Key就是Authorization,对应的值是Bearer + (空格) + Token

以上就是没有Ocelot网关时,IdentityServer的认证流程。

案例五 Ocelot集成IdentityServer服务

在上面的例子中,我是直接将下游服务暴露给客户端调用,当接入Ocelot网关时,我们要达到内外互隔的特性,于是就把IdentityServer服务也托管到Ocelot网关中,这样我们就能统一认证和服务请求时的入口。

于是,我们可以形成下面这个流程图:

根据流程图,我在Ocelot ReRoutes中添加两组路由

  1. {
  2. "DownstreamPathTemplate": "/connect/token",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 8005
  8. }
  9. ],
  10. "UpstreamPathTemplate": "/token",
  11. "UpstreamHttpMethod": [ "Post" ],
  12. "Priority": 2
  13. },
  14. {
  15. "DownstreamPathTemplate": "/api/ocelot/identityWilling",
  16. "DownstreamScheme": "http",
  17. "DownstreamHostAndPorts": [
  18. {
  19. "Host": "localhost",
  20. "Port": 8001
  21. }
  22. ],
  23. "UpstreamPathTemplate": "/ocelot/identityWilling",
  24. "UpstreamHttpMethod": [ "Get" ],
  25. "Priority": 2
  26. }

第一组是将IdentityServer服务进行托管,这样客户端就可以直接通过Ocelot网关访问/token就可以进行认证,第二组是将下游服务进行托管

然后,也是按照之前例子的步骤,先通过http://localhost:4727/token认证,然后将得到的TokenBearer的方式加入到向下游服务的请求当中

结果也是跟我预想的是一致的,可以按照这样的流程进行身份认证。

但是!!!但是!!!但是!!!

当外面随便来一个人,跟前台说他要找我做一件事情,然后前台直接告诉他我的具体位置,就让他进公司找我了,然后当我接待他的时候,我才发现这个人根本就是来搞事的,拒绝他的请求。如果一天来这么几十号人,我还要不要正常干活了?

这明显就不符合实际应用场景,外面的人(客户端)在前台(Ocelot)的时候,就需要进行身份认证(IdentityServer),只有通过认证的人才能进公司(路由),我才会接触到这个人(响应),这才叫专人做专事。

于是,认证流程改为下图:

准备下游服务

为了保证我的案例与上面这个认证流程是一致的,我就把前面在下游服务中的认证配置去掉。而且在实际生产环境中,客户端与下游服务的网络是隔断的,客户端只能通过网关的转发才能向下游服务发出请求。

OcelotDownAPI项目

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. //IdentityServerConfig identityServerConfig = new IdentityServerConfig();
  4. //Configuration.Bind("IdentityServerConfig", identityServerConfig);
  5. //services.AddAuthentication(identityServerConfig.IdentityScheme)
  6. // .AddIdentityServerAuthentication(options =>
  7. // {
  8. // options.RequireHttpsMetadata = false;
  9. // options.Authority = $"http://{identityServerConfig.IP}:{identityServerConfig.Port}";
  10. // options.ApiName = identityServerConfig.ResourceName;
  11. // }
  12. // );
  13. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  14. }
  15. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  16. {
  17. if (env.IsDevelopment())
  18. {
  19. app.UseDeveloperExceptionPage();
  20. }
  21. //app.UseAuthentication();
  22. app.UseMvc();
  23. }

同时也把API接口中的[Authorize]属性去除。

然后将OcelotDownAPI项目重新打包,部署在80018002端口,作为两个独立的下游服务。

配置IdentityServer

回到IdentityServer项目的appsettings.json,在ApiResources中另外添加两个服务

  1. {
  2. "Name": "identityAPIService8001",
  3. "DisplayName": "identityAPIService8001Name"
  4. },
  5. {
  6. "Name": "identityAPIService8002",
  7. "DisplayName": "identityAPIService8002Name"
  8. }

Clients中添加两个Client

  1. {
  2. "ClientId": "markfull",
  3. "ClientSecrets": [ "markjiang7m2" ],
  4. "AllowedGrantTypes": "ClientCredentials",
  5. "AllowedScopes": [ "identityAPIService8001", "identityAPIService8002" ]
  6. },
  7. {
  8. "ClientId": "marklimit",
  9. "ClientSecrets": [ "123456" ],
  10. "AllowedGrantTypes": "ClientCredentials",
  11. "AllowedScopes": [ "identityAPIService8001" ]
  12. }

这里我为了能让大家看出允许访问范围的效果,特意分配了两个不同的AllowedScopes

使用markfull登录的客户端可以同时请求identityAPIService8001identityAPIService8002两个下游服务,而使用marklimit登录的客户端只允许请求identityAPIService8001服务。

Ocelot集成IdentityServer认证

跟前面的例子一样,要支持IdentityServer认证,OcelotDemo项目就需要安装IdentityServer4.AccessTokenValidation包。

OcelotDemo项目的appsettings.json添加IdentityServer信息

  1. "IdentityServerConfig": {
  2. "IP": "localhost",
  3. "Port": 8005,
  4. "IdentityScheme": "Bearer",
  5. "Resources": [
  6. {
  7. "Key": "APIService8001",
  8. "Name": "identityAPIService8001"
  9. },
  10. {
  11. "Key": "APIService8002",
  12. "Name": "identityAPIService8002"
  13. }
  14. ]
  15. }

当然这个配置项的结构是任意的,我这里的Resources数组配置的就是Ocelot网关支持哪些服务的认证,Name就是服务的名称,同时会唯一对应一个Key

为了能更加方便读取IdentityServerConfig的信息,我定义了一个跟它同结构的类

  1. public class IdentityServerConfig
  2. {
  3. public string IP { get; set; }
  4. public string Port { get; set; }
  5. public string IdentityScheme { get; set; }
  6. public List<APIResource> Resources { get; set; }
  7. }
  8. public class APIResource
  9. {
  10. public string Key { get; set; }
  11. public string Name { get; set; }
  12. }

然后来到Startup.csConfigureServices方法,就能很快地将IdentityServer信息进行注册

  1. var identityBuilder = services.AddAuthentication();
  2. IdentityServerConfig identityServerConfig = new IdentityServerConfig();
  3. Configuration.Bind("IdentityServerConfig", identityServerConfig);
  4. if (identityServerConfig != null && identityServerConfig.Resources != null)
  5. {
  6. foreach (var resource in identityServerConfig.Resources)
  7. {
  8. identityBuilder.AddIdentityServerAuthentication(resource.Key, options =>
  9. {
  10. options.Authority = $"http://{identityServerConfig.IP}:{identityServerConfig.Port}";
  11. options.RequireHttpsMetadata = false;
  12. options.ApiName = resource.Name;
  13. options.SupportedTokens = SupportedTokens.Both;
  14. });
  15. }
  16. }

Configure方法中添加

  1. app.UseAuthentication();

最后,就是配置Ocelot.json文件。

ReRoutes中添加两组路由

  1. {
  2. "DownstreamPathTemplate": "/api/ocelot/identityWilling",
  3. "DownstreamScheme": "http",
  4. "DownstreamHostAndPorts": [
  5. {
  6. "Host": "localhost",
  7. "Port": 8001
  8. }
  9. ],
  10. "UpstreamPathTemplate": "/ocelot/8001/identityWilling",
  11. "UpstreamHttpMethod": [ "Get" ],
  12. "Priority": 2,
  13. "AuthenticationOptions": {
  14. "AuthenticationProviderKey": "APIService8001",
  15. "AllowedScopes": []
  16. }
  17. },
  18. {
  19. "DownstreamPathTemplate": "/api/ocelot/identityWilling",
  20. "DownstreamScheme": "http",
  21. "DownstreamHostAndPorts": [
  22. {
  23. "Host": "localhost",
  24. "Port": 8002
  25. }
  26. ],
  27. "UpstreamPathTemplate": "/ocelot/8002/identityWilling",
  28. "UpstreamHttpMethod": [ "Get" ],
  29. "Priority": 2,
  30. "AuthenticationOptions": {
  31. "AuthenticationProviderKey": "APIService8002",
  32. "AllowedScopes": []
  33. }
  34. }

跟其他普通路由相比,这两组路由都多了一个AuthenticationOptions属性,它里面的AuthenticationProviderKey就是我们在前面ConfigureServices方法中登记过的Key

我们来捋顺一下这个路由跟认证授权过程。以markfull的ID和这里的第一组路由为例。

  1. 客户端拿着markfull的clientID向IdentityServer(http://localhost:4727/token)进行认证,得到了一个的Token
  2. 客户端带着这个Token,因此有了markfull的身份,请求Url地址http://localhost:4727/ocelot/8001/identityWilling
  3. Ocelot网关接收到请求,根据路由表找到了认证支持关键字为APIService8001,从而得到了对应的IdentityServer服务信息:IdentityServer服务地址为http://localhost:8005,下游服务名称为identityAPIService8001
  4. Ocelot带着Token向IdentityServer服务(http://localhost:8005)进行配对,即查看markfull身份的访问范围是否包含了identityAPIService8001服务
  5. Ocelot认证过markfull是允许访问的,将请求转发到下游服务中,根据路由配置,下游服务地址为http://localhost:8001/api/ocelot/identityWilling

下面我将Ocelot运行起来,并通过Postman进行验证。

markfull身份认证

使用markfullClientId向IdentityServer进行认证

向8001请求

将得到的Token加入到请求中,请求Url地址http://localhost:4727/ocelot/8001/identityWilling,得到下游服务返回的响应结果

向8002请求

将得到的Token加入到请求中,请求Url地址http://localhost:4727/ocelot/8002/identityWilling,得到下游服务返回的响应结果

然后,更换marklimit身份再验证一遍

marklimit身份认证

使用marklimitClientId向IdentityServer进行认证

向8001请求

将得到的Token加入到请求中,请求Url地址http://localhost:4727/ocelot/8001/identityWilling,得到下游服务返回的响应结果

向8002请求

将得到的Token加入到请求中,请求Url地址http://localhost:4727/ocelot/8002/identityWilling,此时,我们得到了401的状态码,即未授权。

总结

在这篇文章中就跟大家介绍了基于IdentityServer4为认证服务器的Ocelot认证与授权,主要是通过一些案例的实践,让大家理解Ocelot对客户端身份的验证过程,使用了IdentityServer中最简单的客户端认证模式,因为这种模式下IdentityServer的认证没有复杂的层级关系。但通常在我们实际开发时,更多的可能是通过用户密码等方式进行身份认证的,之后我会尽快给大家分享关于IdentityServer如何使用其它模式进行认证。今天就先跟大家介绍到这里,希望大家能持续关注我们。

Ocelot(四)- 认证与授权的更多相关文章

  1. ocelot 自定义认证和授权

    ocelot 自定义认证和授权 Intro 最近又重新启动了网关项目,服务越来越多,每个服务都有一个地址,这无论是对于前端还是后端开发调试都是比较麻烦的,前端需要定义很多 baseUrl,而后端需要没 ...

  2. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(四)

    在上一讲中,我们已经完成了一个完整的案例,在这个案例中,我们可以通过Angular单页面应用(SPA)进行登录,然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证.在 ...

  3. Ocelot简易教程(五)之集成IdentityServer认证以及授权

    Ocelot简易教程目录 Ocelot简易教程(一)之Ocelot是什么 Ocelot简易教程(二)之快速开始1 Ocelot简易教程(二)之快速开始2 Ocelot简易教程(三)之主要特性及路由详解 ...

  4. [转载]Ocelot简易教程(五)之集成IdentityServer认证以及授权

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9807125.html 最近比较懒,所以隔了N天才来继续更新第五篇Ocelot简易教程,本篇教程会先简单介 ...

  5. .Netcore 2.0 Ocelot Api网关教程(5)- 认证和授权

    本文介绍Ocelot中的认证和授权(通过IdentityServer4),本文只使用最简单的IdentityServer,不会对IdentityServer4进行过多讲解. 1.Identity Se ...

  6. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)

    好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名<Angular单页面应用基于Ocelot API网关与IdentityServer4+ASP.NET Iden ...

  7. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(二)

    上文已经介绍了Identity Service的实现过程.今天我们继续,实现一个简单的Weather API和一个基于Ocelot的API网关. 回顾 <Angular SPA基于Ocelot ...

  8. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(三)

    在前面两篇文章中,我介绍了基于IdentityServer4的一个Identity Service的实现,并且实现了一个Weather API和基于Ocelot的API网关,然后实现了通过Ocelot ...

  9. gRPC四种模式、认证和授权实战演示,必赞~~~

    前言 上一篇对gRPC进行简单介绍,并通过示例体验了一下开发过程.接下来说说实际开发常用功能,如:gRPC的四种模式.gRPC集成JWT做认证和授权等. 正文 1. gRPC四种模式服务 以下案例演示 ...

随机推荐

  1. 仿联想商城laravel实战---1、仿联想商城需求和数据库设计(lavarel如何搭建项目)

    仿联想商城laravel实战---1.仿联想商城需求和数据库设计(lavarel如何搭建项目) 一.总结 一句话总结: composer引入lavarel.配置域名.配置apache 1.项目名 le ...

  2. php数据结构课程---1、数据结构基础介绍(程序是什么)

    php数据结构课程---1.数据结构基础介绍(程序是什么) 一.总结 一句话总结: 程序=数据结构+算法 设计好数据结构,程序就等于成功了一半. 数据结构是程序设计的基石. 1.数据的逻辑结构和物理结 ...

  3. 关于数组的初始化memset函数

    关于数组的初始化memset函数 其实memset复制时按bit8个8个的赋值,有兴趣的可以自己百度.

  4. define的用法与注意事项

    ------------------------------------------------- 在编程使用宏替换时,当字符串中不只一个符号时,加上括号表现出优先级, 如果是带参数的宏定义,则要给宏 ...

  5. 关于React前端构建的一般过程 - 理论篇

    概要 本文以个人阅读实践经验归纳前端架构构建过程,以Step by Step方式说明创建一个前端项目的过程.并会对每个阶段所使用的技术进行可替代分析,如Express替换Hapi或者Koa的优缺点分析 ...

  6. zoj1360/poj1328 Radar Installation(贪心)

    对每个岛屿,能覆盖它的雷达位于线段[x-sqrt(d*d-y*y),x+sqrt(d*d+y*y)],那么把每个岛屿对应的线段求出来后,其实就转化成了经典的贪心法案例:区间选点问题.数轴上有n个闭区间 ...

  7. PS色调— —通道混合

    clc; clear all; close all; addpath('E:\PhotoShop Algortihm\Image Processing\PS Algorithm'); Image=im ...

  8. 通过rtmpdump推送海康视频流到red5服务器

    现在主流的网络摄像机都支持标准H264视频格式,例如 海康网络摄像机, 通过海康提供的网络SDK可以获取到视频码流.我测试的这款相机,视频编码采用的是H264,音频编码采用的是G711a. 这里,我仅 ...

  9. java web项目创建

    https://www.cnblogs.com/kangjianwei101/p/5621738.html

  10. 杂项-权限管理:RBAC

    ylbtech-杂项-权限管理:RBAC 基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注.在RBAC中, ...