微服务架构下的统一身份认证和授权

一、预备知识

本文讨论基于微服务架构下的身份认证和用户授权的技术方案,在阅读之前,最好先熟悉并理解以下几个知识点:

  • 微服务架构相关概念:服务注册、服务发现、API 网关
  • 身份认证和用户授权:SSO、CAS、OAuth2.0、JWT

文章在涉及到上述知识内容时,会附上参考链接。此外,还有以下几个基础概念,在身份治理领域容易混淆:

  • 认证
  • 授权
  • 鉴权
  • 权限控制

建议参考 pphh 的博文《认证、授权、鉴权和权限控制》:

http://www.hyhblog.cn/2018/04/25/user_login_auth_terms

二、背景

当企业的应用系统逐渐增多后,每个系统单独管理各自的用户数据容易行成信息孤岛,分散的用户管理模式阻碍了企业应用向平台化演进。当企业的互联网业务发展到一定规模,构建统一的标准化账户管理体系将是必不可少的,因为它是企业互联网云平台的重要基础设施,能够为平台带来统一的帐号管理、身份认证、用户授权等基础能力,为企业带来诸如跨系统单点登录、第三方授权登录等基础能力,为构建开放平台和业务生态提供了必要条件。

三、需求分析

在微服务架构下,必须对企业的平台生态进行合理的业务划分,每个业务板块将自成系统,例如负责宣发的企业官网、主打文体的 B2B2C 商城、面向社区的物业服务系统等,这些系统业务比较独立,应当独立拆分。每个系统又可根据各自的业务模型进行切分,将业务模型和用户需求统筹分析后建立恰当的领域模型,形成独立的服务。

另外,企业平台的客户范围比较复杂,有 2B 的业务,也有 2C 的,还有 2G(goverment)的,因此平台级的统一身份管理必须涉及组织实体和个人实体两类,其中组织实体包括政府机关(G)、企业单位(B)、团体组织(B)等,这类似于多租户架构的概念,但又比传统多租户架构复杂。

一)统一身份管理(Unified Identity Manager)

统一身份管理(UIM)是整个平台帐号和权限管控的基础,由此构建的系统称为UIMS(Unified Identity Management System),平台下所有系统的账户管理、身份认证、用户授权、权限控制等行为都经由 UIMS 处理,提供帐号密码管理、基本资料管理、角色权限管理等功能。UIMS 基于『统一身份治理』的概念,可划分为两级账户体系、基础权限模块和基础信息模块三大模块。其中两级账户体系将账户分为组织实体帐号和个人实体账户两大类,个人实体从属于组织实体,也可以不从属任何组织实体,且个人实体可同时从属于多个组织实体;基础权限模块将各业务系统的资源权限进行统一管理和授权;基础信息模块用于描述组织实体和个人实体的基本信息,如组织实体名称、地址、法人,个人实体姓名、电话号码、性别等基础信息。UIMS 提供统一的 API 与各子系统连接。

可以看到,众多系统和众多服务都将依赖于 UIMS 。本文仅涉及 UIMS 下的两级账户体系和基础权限模块这两个模块,据此可以独立出账户管理服务和权限管理服务,也可以合并成一个账户权限管理服务。其中账户管理服务包括业务系统实体、组织实体和个人实体管理、权限管理服务包含认证、授权和鉴权三个部分。

关于统一身份管理系统的介绍,请参考 https://mtide.net/平台级SaaS架构的基础-统一身份管理系统.html

二)软件即服务(SaaS)

企业提供对外的 IT 服务,有两种部署模式:一是私有云部署,二是公有化服务。公有云服务即 SaaS,提供系统级的应用服务,包括企业服务如企业邮箱、办公 OA、人力资源系统等,个人服务如个人邮箱、云笔记、云网盘等。平台级的 SaaS 应用架构,实际上可以理解为多租户架构的升级版,加大了统一身份治理的难度。而基于 UIMS 系统的两级账户体系,可以很容易做到这一点。值得注意的是,有些系统仅提供个人账户服务,有些系统仅提供组织账户服务,有的则两者都提供,必须处理好个人实体和组织实体之间的关系。

关于 SaaS 的介绍,请参考 http://www.ruanyifeng.com/blog/2017/07/iaas-paas-saas.html

三)组织实体(Orginization Entity)

在 UIMS 中,组织机构应当是一种实体,与之对应的另一种实体是个人实体。注意实体(Entity)不是账户(Account),因此要设计一种用于组织实体登入受控系统的方法,这里有两种可选方案:一是增加组织实体账户,组织实体自身拥有账户,可直接进行认证登录;二是将从属于组织实体的个人账户作为组织实体的登入凭证。无论何种方法,在认证和授权时,都应当向 UIMS 提供统一的标准的账户凭证,凭证的规格由 UIMS 定义,因此,组织实体的认证授权与个人实体的认证授权并无二致。

四)单点登录(SSO)

企业平台涉及众多子系统,为简化各子系统的用户管理,提升用户体验,因此实现 SSO 是统一身份认证的重要目标:一次登录,全部访问。对于企业内部应用来说,SSO 是必须的选项,例如企业 OA、HR、CRM 等内部系统;对于外部应用来说,SSO 是可选项,具体哪个应用应当加入 SSO 系统,由该业务系统决定,例如外部商城、物业系统等对外服务系统。无论何种应用是否采用 SSO,UIMS 在技术上应当具备 SSO 的能力。

关于SSO的介绍,请参考 https://www.cnblogs.com/EzrealLiu/p/5559255.html

五)授权登录

随着平台业务的逐渐增长,依托于平台的,和平台依托的厂商和客户等资源将极大的丰富平台,因此必须构筑开放的生态系统,以支撑业务的进一步发展。可以开放平台级的授权登录功能,以允许第三方应用接入。通过三方授权登录,将平台的服务各能力开发给第三方,并将第三方的服务和能力接入平台,繁荣共生,共同发展。

六)服务间鉴权

业务系统切分出不同的服务,根据粒度粗细和业务需求不同,服务的数量和权限要求都不同。微服务架构下的身份认证和授权,可分为两种:

  • 内部服务的认证和授权;
  • 外部服务的认证和授权。

通常,内部服务处于安全的内网环境之下,例如 BFF 层(Backend For Frontend Layer)的商品服务、订单服务等,在对安全需求不高的情况下,可不执行认证过程,服务与服务之间是相互信任的。

而外部服务的认证和授权,通常由外部应用发起,通过反向代理或网关向安全边界内的服务发起请求,因此必须执行严格的认证过程。无线端APP、Web端、桌面客户端等外部应用下的各类服务,都属于外部服务。

服务间鉴权示意图

七)帐号登出和销毁

与 SSO 相对应,UIMS 应该支持一次登出,全部登出,即 SSOff(Single Sign-Off,非标准术语);或者一次登出,部分登出,而是否全部登出或部分登出取决于用户的选择,例如用户在 Web 端登出后,是否无线端 APP 也登出,这取决于用户偏好,但系统应当提供这种能力。

此外,必须提供统一的销毁功能,以支持用户删除其账户,一次销毁,全部销毁。

八)付费授权

云平台应具备付费授权机制,针对用户账户和组织账户进行独立授权。根据产品的商业策略,可执行灵活的付费模式:

  • 时效限制:年付、季付、月付,不同时效费用不同;
  • 功能限制:授权不同的功能,费用不同;
  • 数量限制:最大组织数量限制、最大用户数量限制,不同的数量费用不同。

四、技术方案

一)备选方案

上文基于『统一身份治理』的理念,提出了统一身份管理系统(UIMS)下关于身份认证和授权部分的主要需求。目前实现统一身份认证和授权的技术手段较多,总体可以归纳为以下两类:

  1. 传统的 Cookie + Session 解决方案,有状态会话模式;
  2. 基于令牌/票据的解决方案,无状态交互模式。

具体有:

  • 分布式 Session
  • OAuth2.0
  • CAS

上述方案各有利弊:

  • 分布式 Session 是老牌的成熟解决方案,但因其状态化通信的特性与微服务提倡的API导向无状态通信相互违背,且共享式存储存在安全隐患,因此微服务一般不太采用。

  • OAuth2.0 是业内成熟的授权登录解决方案,然而 OA2.0 提供了4种授权模式,能够适应多种场景,作为基于令牌的安全框架,可以广泛用于需要统一身份认证和授权的场景。

关于 OAuth2.0 的介绍,请参考 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

在 OAuth2.0 的实施过程中,一般会采用 JWT 作为令牌的主要标准:JWT(JSON Web Token)是一种简洁的自包含的 JSON 声明规范,因其分散存储和自解签等特点而广泛应用于非集中式认证/授权场景。由于 JWT 信息是经过签名的,可以确保发送方的真实性,确保信息未经篡改和伪造。但由于其自包含的客户端验签特性,令牌一经签发,即无法撤销,因此单纯采用 JWT 作为统一身份认证和授权方案无法满足帐号统一登出和销毁、帐号封禁和解除这几种类型的需求,所以一般配合 OAuth2.0 一起使用。

关于 JWT 的介绍,请参考 http://blog.leapoahead.com/2015/09/06/understanding-jwt/

  • CAS 是时下最成熟的开源单点登录方案,包含 CAS Server 和 CAS Client 两部分。CAS Server 是一个 war 包需要独立部署,负责用户认证;CAS Client 负责处理对客户端受保护资源的访问请求,需要认证时,重定向到 CAS Server。值得注意的是,CAS 是一个认证框架,其本身定义了一套灵活完整的认证流程,但其兼容主流的认证和授权协议如 OAuth2、SAML、OpenID 等,因此一般采用 CAS + OAuth2 的方案实现 SSO 和授权登录。

关于 CAS 的介绍,请参考 https://apereo.github.io/cas/

在微服务架构下,身份认证和用户授权通常分离出来成为独立的 IDP (Identity Provider)服务。在做技术选型时,应从以下几点考虑:

  1. 满足 SSO 的技术需求;
  2. 满足简便性和安全性的需求;
  3. 满足开放性和扩展性的需求。

综合考虑,推荐采用无状态 API 模式,其中基于 OAuth2.0 的方案能够完全满足。

场景假设:构建基于图像的物品识别系统(Image-Based Classification System)

为便于理解统一认证和授权方案的细节,假定一种场景:团队准备构建一套基于图像的物品识别系统,允许用户通过 H5 应用或 APP 上传图像,系统分析后返回识别结果;同时期望将此系统开放给社区和行业用户以便商用;最后允许第三方应用将自身的功能接入 IBCS 以增强后者的能力。

下图是该系统的微服务架构图:

IBCS 微服务架构图

在微服务架构下,IBCS 分为内外两层,内层处于物理内网环境下,也称为内部服务,外层处于物理外网环境下,也称为外部服务,内外通过 API 网关连接。

  • 内部服务:IDP 服务、配置服务、图像识别服务属于内部服务,通常内部服务之间是相互信任的,但在安全要求较高的场景下,内部服务也不能互信。
  • 外部服务:桌面 APP、无线 APP、H5、第三方应用属于外部服务,外部服务分为两种类型:一种是第一方应用,即 IBCS 的一部分,如 IBCS 的 APP、H5 这些自家前端和无线端应用;另一种是 IBCS 之外的第三方应用。两种类型的授权方式是不一样的,前者一般采用 OAuth2.0 的密码模式,后者则采用授权码模式。

下文将以物品识别系统为例子,介绍这两种推荐方案:

二)最佳方案: OAuth2.0

1. OAuth2.0 的四种授权模式

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

其中密码模式常用于外部服务的认证、授权和鉴权,客户端模式常用于内部服务的认证、授权和鉴权和开放平台应用的授权,授权码模式常用于社会化登录和 SSO,因此 OAuth2.0 可作为完整的统一身份认证和授权方案。

2. OAuth2.0 的几种重要角色

必须注意的是,这些角色是相对的概念。

  • 客户端 Client:一般指第三方应用程序,例如用 QQ 登录豆瓣网站,这里的豆瓣网就是 Client;但在微服务体系里,Client 通常是服务本身,如 APP 端的注册登录服务;
  • 资源所有者 Resource Owner:一般指用户,例如用 QQ 登录豆瓣网站,这里的所有者便是用户;但在微服务体系里,资源所有者是服务提供者本身;
  • 资源服务器 Resource Server:一般指资源所有者授权存放用户资源的服务器,例如用 QQ 登录豆瓣网站,这里的 QQ 就是资源服务器;但在微服务体系里,服务提供者本身便是资源服务器;
  • 授权服务器 Authorization Server:一般是指服务提供商的授权服务,例如用 QQ 登录豆瓣网站,这里的 QQ 便是授权服务器;类似地,在微服务体系里,IDP 服务便是授权服务器。

3. IBCS 提供哪些功能

1)核心功能,以 API 形式暴露:

接口描述body返回权限
POST /image-classify图像识别{ 图片内容, token }{ 识别结果 }受控接口

2)由 UIMS 提供的功能:

功能/API描述body返回权限
POST /accounts/注册接口{ username, password }{ sign-up-result }非受控接口
POST /accounts/login登录接口{ username, password }{ token }受控接口
POST /accounts/logout登出接口{ token }{ logout-result }受控接口
SignUp-Page统一注册页面(UI)非受控页面
Login-Page统一登录页面(UI)非受控页面

其中,注册接口、SignUp-Page 和 Login-Page 页面是非受控接口/页面,意味着无须鉴权即可访问。

SignUp-Page 和 Login-Page 页面是由 UIMS 提供的统一的注册和登录页面,当外部服务发起注册或登录请求时,有两种作法:一是统一跳转到 UIMS 的注册或登录页面,用户完成操作后调用 UIMS 的注册和登录 API 完成请求;二是在自己的注册和登录页面完成操作,然后以用户名和密码作为参数调用 UIMS 的注册和登录 API 完成请求。推荐采用第一种方法,类似于全网通行证,用户体验统一,不用重复开发注册登录页面。

3)成为开发者,获取 IBCS 的能力集:

  1. 第一步:申请成为开发者。开发者分为个人开发者和组织开发者两类,实名认证也分两种类型进行。成为开发者的前提是成为平台的注册用户;
  2. 第二步:创建应用,平台审核通过后,生成 AppId 和 AppSecret 给到开发者,每个应用对应一对 AppId 和 AppSecret。值得注意的是,每个 AppID 与用户账号是绑定的,因此每个 AppId 获取资源和能力的权限受到该用户账户权限的限制,典型的例子是对象存储服务(OSS/OBS);
  3. 第三步:获取 Access Token,开发者按照 OAuth2.0 的规范,采用客户端(client_credentials)模式,利用申请到的 AppId 和 AppSecret 向 IBCS 申请 token;
  4. 第三步:使用 Access Token 与平台进行交互,每次调用受控 API 时都携带此 token。

在更高安全性要求的场景下,也会采用授权码模式。

4)成为开发者,创建第三方应用:

一般来说,应当独立建设一个开放平台,开发平台作为整个云平台的一个子系统,同样依赖于 UIMS。在开放平台上,应当提供一套完善的界面和流程,以引导用户完成开发者认证和第三方应用接入的所有工作。此外,在前期阶段,也可以采用线下申请的方式,由管理员人工审核,在后台手动录入。

在开放平台上,创建第三方应用的流程和步骤,与上一步骤『成为开发者,获取 IBCS 的能力集』一致。所不同的是,上个步骤是获取 IBCS 的能力,而本步骤『创建第三方应用』,是基于开放平台开发应用,类似于微信小程序。

5)成为开发者,将异构系统(第三方应用)接入 IBCS:

应该允许开发者将异构系统(第三方应用)接入 IBCS,以增强 IBCS 的能力。例如,假设 IBCS 本身不具备识别特种汽车的能力,但允许接入其他开发者开发的基于图像的特种汽车识别应用。

第三方应用接入,归属于开放平台的范畴。接入的流程和步骤,与第三步骤『成为开发者,获取 IBCS 的能力集』一致,由开放平台提供标准的 API,第三方按照接入规范执行。

4. OAuth2.0 四种授权模式的应用场景

场景描述适用模式
用户注册(外部服务)用户在 APP 提供的注册页面,完成注册请求非受控接口,无须鉴权
用户登录(外部服务),返回 token用户在 APP 提供的登录页面,完成登录请求,获得 token密码模式(resource owner password credentials)
用户注册(UIMS)用户跳转到 UIMS 的注册页面,完成注册请求,注册成功后,跳回到原服务非受控接口,无须鉴权
用户登录(UIMS),返回 token用户跳转到 UIMS 的登录页面,完成登录操作,获得授权码,然后携带授权码跳转到重定向URI,再获得 token授权码模式(authorization code)
外部服务的鉴权用户在 APP 上使用图像识别服务,APP 调用 IBCS 的图像识别 API 并返回结果给用户密码模式(resource owner password credentials)
内部服务的鉴权图像识别服务向配置服务获取配置信息客户端模式(client credentials),或简单的 HTTP Basic 验证
开发者:获取 IBCS 能力集客户端模式(client credentials)或授权码模式(authorization code)
开发者:创建第三方应用客户端模式(client credentials)或授权码模式(authorization code)
开发者:接入第三方应用客户端模式(client credentials)或授权码模式(authorization code)

5. 客户端鉴权和用户鉴权

服务鉴权,从形式上分为:

  1. 非受控服务/接口,无须认证或鉴权;
  2. 客户端认证或鉴权(服务自身认证或鉴权):客户端(服务)在访问另一个服务时,必须先表明客户端自己的身份;
  3. 业务认证或鉴权(用户认证或鉴权):用户通过客户端(服务)访问某个资源时,必须验证用户自己的身份。

例如,用户通过 APP 登录 IBCS 后,访问图像识别服务的过程:用户登录后获得 token,由 APP 携带此 token 向图像识别服务发起请求,图像识别服务首先调用 IDP 服务验证 APP 的身份(通过 ClientId 和 ClientSecret),然后再验证用户的身份(通过 token),如果 APP 和用户都获得授权,则请求通过,返回识别结果。

6. 跨域问题

浏览器的同源策略给 Web 应用划定了安全边界,是 Web 应用安全模型的重要基础。基于令牌的安全系统,在同源策略的约束下面临两个问题:

  1. 跨域请求;
  2. SSO 登录状态的跨域保持。

1)CORS 方案

第一个问题,一般采用 CORS 方案,在服务端的响应头声明 Access-Control-Allow-Origin 参数即可解决跨域请求的问题。

2)同域 SSO 方案

第二个问题,在同域环境下,传统方法是采用 Cookie 的方案。跨域环境下,也有几种方案,从安全性和简便性考虑,推荐采用这种方案:

  • 根据业务需求将应用切分为同域 SSO 应用和跨域 SSO 应用两类;
  • 将需要 SSO 状态保持的应用归到同域 SSO 应用中,将其他应用归到跨域 SSO 应用中;
  • 对于同域 SSO 应用,一般是企业内部应用,或相关性较高的应用,这些应用的域名采用相同的父级域名,继续使用 Cookie 方案;
  • 对于跨域 SSO 应用,不提供 SSO 状态保持。当用户首次打开此类应用时,由于 Cookie 无法跨域,因此服务端无法感知用户的登录状态,此时用户是处于未登录状态的;当用户访问受控页面或点击登录页面时,须重新执行登录操作。

7. 登出和关闭账户

OAuth2.0 是集中式的令牌安全系统,可以通过撤销令牌登出系统。关闭账户与此类似。

8. 软件授权

可在 IDP 服务或 API 网关增加规则过滤器,将商业授权策略应用到授权规则中。

9. 技术选型

后续会写实践篇,敬请期待……

三)将 JWT 应用到 OAuth2.0 方案中

JWT 是一种自包含的客户端令牌系统技术规范,这是其与 OAuth2.0 默认令牌的最大不同,在应用 JWT 时,有几个要点须加以说明。

1. 搭配 API 网关实现令牌撤销

由于 JWT 属于自包含的客户端令牌系统,令牌发出后无须服务器验证,只需在客户端验证。客户端验证并解签后将得到必要的信息,例如用户基本信息和权限标识符。这种设计天然地存在无法撤销令牌的问题。解决方案是网关之外的外部服务继续使用 OAuth2.0 的 AccessToken,在网关以内的内部服务使用 JWT,这样做有几个好处:

  1. 外部服务处在不安全的场景中,OAuth2.0 的 AccessToken 本身是一串无意义的字符串,并非结构化数据,这加强了令牌的安全性;
  2. 有效解决 JWT 无法撤销的问题:OAuth2.0 的 AccessToken 仍然是集中式的令牌系统,外部服务请求资源时会携带 AccessToken 经过网关的拦截。

不过此方案仍然存在两个问题:

  1. 将一定程度丧失 JWT 客户端解签的优势,因为外部服务仍然采用 OAuth2.0 的 AccessToken,但相较于传统的 Cookie + Session 方案,此方案更加轻巧,也更加符合微服务无状态 API 的风格;
  2. 对于已发出的 AccessToken,客户端在下一次请求之前,服务端的令牌系统对此没有控制能力,例如 SSOff 将无法很好地实现。

2. 客户端认证/鉴权和用户认证/鉴权

与 OAuth2.0 方案一致,客户端同样需要使用 ClientId 和 ClientSecret 认证/鉴权。

3. 公钥和密钥

JWT 一般采用非对称加密算法对 Header 和 Payload 进行签名,公钥可以公开存储在外部服务中,如 H5、APP。

1)非对称算法

非对称算法的重要特点是,使用密钥加密时,必须用公钥解密;用公钥加密时,必须用密钥解密。利用此特性,通常在服务端采用密钥加密信息,然后客户端采用公钥解密信息。由于密钥存储在服务端,因此安全性高;公钥本身可以公开,因此可以在客户端存储。

2)公钥解密

JWT 经由服务端用密钥加密后,发往客户端,客户端使用公钥进行解密,便得到了 JWT 的明文。JWT 包含了丰富的信息(通常是用户基本信息和权限标识符),客户端完全可以信任此 JWT,因此不必再依赖于服务端重复鉴权。

4. 服务间认证/鉴权

1)内部服务认证/鉴权

以 IBCS 为例,当图像识别服务服务携带 JWT 向配置服务请求资源时,配置服务使用公钥解密,配置服务完全可以信任图像识别服务,因此也不必再依赖于鉴权服务的重复认证/鉴权。对于安全性要求不高的场景,也可以使用 HTTP Basic 验证进行简单认证/鉴权甚至不认证/鉴权。

2)外部服务认证/鉴权

同样,外部的 APP 携带 Oauth AccessToken 向内网的图像识别服务发起请求时,属于外部服务向内网服务发起请求,必须经过 API 网关,由网关执行规则过滤和代理认证(网关向 IDP 请求校验令牌),确保 AccessToken 仍处于有效状态,如果 Token 通过检验,则由 IDP 生成包含权限标识(或Scope)的 JWT 返回给网关,网关拿到 JWT 后利用公钥进行解密,并校验权限标识(或Scope),通过后再携带此 JWT 向图像识别服务转发请求,图像识别服务收到请求后,利用公钥解密 JWT 并自行检验其有效性、获取用户信息等,无须再请求 IDP。

必须留意,在网关拿到 JWT 以后,虽然可以连同 Oauth AccessToken 一起缓存,下次该服务再发起请求时,可直接转发 JWT 而不用再经由 IDP 的进行 JWT 令牌转换,但这么做有两个问题:

  1. 在一定程度上,网关抢夺了 IDP 的鉴权工作;
  2. 如果网关不执行令牌有效性(过期时间等)的检验,而是简单通过 Oauth AccessToken 查找出 JWT,则丧失了 IDP 集中鉴权的优势。

所以,综上所述,不建议网关缓存 JWT 并直接转发。

5. 跨域问题

与 OAuth2.0 的跨域解决方案一致。

五、总结

本文给出了微服务架构下的统一身份认证和授权的设计方案,从平台级 SaaS 模式下『统一身份治理』的概念出发,梳理了关键的需求点,提出了对应的解决方案。其中 OAuth2.0 是最佳解决方案,不过在实际运用中,应当遵循『合适原则』、『简单原则』和『演化原则』三个原则,不能盲目照搬。

六、参考链接

  1. 认证、授权、鉴权和权限控制, http://www.hyhblog.cn/2018/04/25/user_login_auth_terms
  2. SaaS,http://www.ruanyifeng.com/blog/2017/07/iaas-paas-saas.html
  3. SSO, https://www.cnblogs.com/EzrealLiu/p/5559255.html
  4. CAS, https://apereo.github.io/cas/
  5. UIMS, https://mtide.net/%E5%B9%B3%E5%8F%B0%E7%BA%A7SAAS%E6%9E%B6%E6%9E%84%E7%9A%84%E5%9F%BA%E7%A1%80-%E7%BB%9F%E4%B8%80%E8%BA%AB%E4%BB%BD%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F.html



作者:mtide
链接:https://www.jianshu.com/p/2571f6a4e192
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用vh来制作高度自适应页面和元素垂直居中

为什么80%的码农都做不了架构师?>>> vh单位 vh是CSS3中的一个长度单位,其值为:100vh 视窗高度。即如果窗口高度为500px,那么 1vh 5px。具体的值会随着浏览器视窗高度的改变而实时改变,因此可以利用这个单…

传智168期JavaEE struts2杜宏 day32~day33(2017年2月15日23:27:09)

struts2学习完毕,寒假学习效率还不错。 笔记链接 链接:http://pan.baidu.com/s/1boBJLVp 密码:wwl4转载于:https://www.cnblogs.com/huangtao1996/p/6403886.html

GitLab的安装、配置、使用

前言上周去参与“中国数字经济创新发展大会”了,然后又忙新项目的事情,博客又有一段时间没有更新,今天周一事情比较少,立刻开始写文,最近有挺多值得记录的东西~进入正文,最近我们搭了个Gitlab,并…

【BIM入门实战】Navisworks2018简体中文安装教程(附安装包下载)

Navisworks是Autodesk公司开发的一款三维模型可视化软件,它以轻量化的运行方式进行BIM成果的后期处理及整合,是一款非常实用的软件。基于Navisworks,项目的参建方可以在施工前进行模拟施工,以达到减少返工、缩短工期、提供经济效益的目的。 Navisworks同时支持4D和5D模拟,…

微软 Windows11 Build 22000.71 更新(KB5004252)发布

微软推出了一个全新的娱乐小工具。这一部件允许用户查看 Microsoft Store 中可用的新电影和精选电影。选择一部电影会引导用户到 Microsoft Store 查看有关该影片的更多信息。 7 月 16 日消息 今日凌晨,微软宣布向预览体验计划用户发布 Windows 11 Build22000.71 更…

【BIM入门实战】Revit模型导入到第三方软件方法汇总

本文以案例的方式,汇总展示了Revit模型导入到ArcGIS Pro、3ds max、Navisworks、Lumion、InfraWorks等的方法。 文章目录 1. Revit导入ArcGIS Pro2. Revit导入3ds Max3. Revit导入Navisworks4. Revit导入Lumion5. Revit导入InfraWorks1. Revit导入ArcGIS Pro ArcGIS Pro2.8可…

Blazor University (37)JavaScript 互操作 —— JavaScript 启动过程

原文链接:https://blazor-university.com/javascript-interop/javascript-boot-process/JavaScript 启动过程在 Blazor 启动过程中,浏览器将在 Blazor 初始化之前创建 HTML 文档,这意味着从引导 HTML 引用的任何 JavaScript 都将立即加载&…

时代聚焦AI安全——可解释性

今年的NIPS多集中在人工智能安全上,此外精彩的部分还有凯特克劳福德关于人工智能公平性问题上被忽视的主题演讲、ML安全研讨会、以及关于“我们是否需要可解释性?”可解释ML讨论会辩论。 值校准文件 逆向奖励设计是为了解决RL代理根据人类设计的代理奖励…

【BIM入门实战】渲染器Vray for 3d max 2018图文安装教程

VRay是由chaosgroup和asgvis公司出品的一款高质量渲染软件。VRay是业界最受欢迎的渲染引擎。基于V-Ray 内核开发的有VRay for 3ds max、Maya、Sketchup、Rhino等诸多版本,为不同领域的优秀3D建模软件提供了高质量的图片和动画渲染。方便使用者渲染各种图片。 Vray for 3d max …

Android--Activity四种启动模式

launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象&…

Hibernate初探

Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 提供的方法完成持久层操作。程序员甚至…

【BIM入门实战】InfraWorks2018图文安装教程

Autodesk InfraWorks是易于使用的草图绘制工具,适用于土地规划师和基础设施设计师。AutodeskInfraWorks可以生成可视化的高级模型,而无需借助辅助,可以独立进行建模的BIM可视化软件。 InfraWorks2018软件预览: 双击安装包进行安装。 自解压中,等待即可。 点击【安装】。 点…

有点酷,使用 .NET MAUI 探索太空

设计 我准备用 .NET Maui 实现一个非常有意思的 "前往太空" 的程序。第一步,需要图片素材,我使用了 Aan Ragil 的一组非常棒的 Dribbble 素材图片。当然,你也可以在最下面的链接进行下载。实现 这个应用程序的完整源代码可以在 G…

实例讲解——系统登录

一,程序分析 首先使用参数的方式输入用户名和密码,所以,首先要判断输入参数的个数是否合法,如果不合法,则必须提示程序执行不对,并退出。 如果正确输入,则可以进行密码和用户名的验证&#xff0…

【Microsoft Office】Word 2019空格下划线不显示的解决办法

解决办法:点击【文件】→【选项】→【高级】选项卡→勾选【为尾部空格添加下划线(U)】,解决!

1.安装

转自:http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。 所谓"测试框…

SkiaSharp 之 WPF 自绘弹跳球(案例版)

熟悉下SkiaSharp的基础操作,这次搞个弹跳球效果,实现后,发现效果还真不错。大概效果如下:原理分析先是实现了网格效果,这个比较简单,直接横线,竖线,就OK了。另外一个就是随机一个圆形&#xff0…

Windows11 发布更新 Insider Preview Build 22000.100

微软今天凌晨向开发频道中的所有用户发布Windows 11 Insider Preview Build 22000.100! 变化和改进 我们已经开始在 Dev Channel 中将 Chat 从 Microsoft Teams 推广到 Insiders。不是每个人都会马上看到,任务栏右下方的隐藏图标弹出窗口已更新&#x…

常见RGB格式

计算机世界中,最终对于颜色和画面的显示,更多的采用的是RGB模式,这里记录一下常见的RGB格式。任何计算机设备以及智能终端等,呈现在我们眼前的色彩实际上便是红绿蓝三基色不同的组合,RGB实际上就是三基色的组合&#x…

《ASP.NET Core 6框架揭秘》实例演示[04]:自定义依赖注入框架

ASP.NET Core框架建立在一个依赖注入框架之上,已注入的方式消费服务已经成为了ASP.NET Core基本的编程模式。为了使读者能够更好地理解原生的注入框架框架,我按照类似的设计创建了一个简易版本的依赖注入框架,并它命名为“Cat”。本篇提供的四…