Chrome80调整SameSite策略对IdentityServer4的影响以及处理方案(翻译)

首先,好消息是Google将于2020年2月份发布Chrome 80版本。本次发布将推进Google的“渐进改良Cookie”策略,打造一个更为安全和保障用户隐私的网络环境。 坏消息是,本次更新可能导致浏览器无法向服务端发送Cookie。如果你有多个不同域名的应用,部分用户很有可能出现会话时常被打断的情况,还有部分用户可能无法正常登出系统。 本篇博客将处理第一个问题(无法发送cookie到服务端)。至于第二个问题(cookie无法被删除),请参考另一篇博客。 首先,SameSite是什么 互联网是十分开放的平台:Cookie诞生于二十多年前,于2011年修订(RFC 6265)。当时跨站访问攻击(CSRF)没有现在这么猖獗,侵犯用户隐私的行为也不像现在这样泛滥。 简而言之,Cookie标准规范规定,如果某域名下设置了Cookie,不管你是直接跳转到该域名,或是加载了该域名的某些资源(例如图片),或是向该域名发送POST请求,亦或将其嵌入iframe,浏览器访问该域名的每次请求,都将带上这个Cookie。 对于iframe嵌入的场景,你可能不希望浏览器将用户会话cookie自动发送到服务器,因为这样任何其他网站都可以在用户不知情的情况下,用他的会话上下文,跟你的服务器发送请求。 为了避免这种情况,SameSite cookie规范于2016年起草。对于发送cookie我们有了更多的控制权:现在可以明确指定每个cookie是否被发送。规范引入了同站/跨站cookie的概念,如果浏览器访问A域名,请求服务端也是A域名,这些cookie就叫同站cookies(same-site cookies),如果浏览器访问A域名,请求服务端是B域名,这些cookie就叫跨站cookies(cross-site cookies)。 为了向后兼容,same-site的默认设置并未改变之前的行为。你必须手动指定SameSite=Lax或者SameSite=Strict,来能使用这项特性加固安全。所有的.NET框架和常见的浏览器都已支持这一特性。设置为Lax,大多数情况不允许发送第三方Cookie,导航到目标网址的Get请求除外。设置为Strict,完全禁止第三方Cookie,除非你之前访问过该域名而Cookie已经存在于浏览器。 悲哀的是,这项新特性的采用率低的可怜(基于Chrome2019年3月份统计显示,在所有的cookie中,只有0.1%使用了SameSite标志)。 Google决定推进这项特性的使用。他们决定修改世界上最多人使用的浏览器——Chrome的默认设置:如果想保持之前处理cookie的方式,Chrome 80要求显示指定SameSite=None。如果像以前一样忽略SameSite属性,Chrome将视作SameSite=Lax。 请注意:SameSite=None只有在Cookie同时被标记为Secure并且使用https连接时才会生效。 更新:如果你想知道关于SameSite cookies的更多背景知识,请扩展阅读这篇文章。 这会影响我吗?什么影响? 如果你有一个单页应用(SPA),使用另一域名的认证服务(比如IdentityServer4)进行身份认证,并且使用了所谓的静默令牌刷新的话,你将受影响。 译者注:使用refresh_token刷新access_token,用户无感知 登录到认证服务的时候,它会为当前用户设置会话cookie,这个cookie属于认证服务域名。认证流程结束之后,另一域名会收到认证服务颁发的access token,有效期通常不会太长。当access token过期之后,应用无法访问api,用户需要频繁的登录,体验十分差。 为了避免这一情况,我们可以使用refresh_token实现静默刷新。应用创建一个用户不可见的iframe,在iframe中进行新的认证流程。iframe中加载了认证服务站点,当浏览器发送会话cookie的时候,认证服务识别出当前用户然后颁发新的token。 SPA网站使用iframe嵌入了认证服务站点的内容,这就是一个跨站请求,只有将iframe中属于认证服务站点的cookie设置为SameSite=None,Chrome 80才会将iframe中的cookie发送到认证服务。否则,token静默刷新将无法正常运行。 可能还会导致一些其他的问题:如果应用中嵌入了其他域名的资源,比如视频自动播放设置,它们需要cookie才能正常运行。某些依赖cookie认证来访问第三方API的应用也会出现问题。 注意:很显然你只能修改自己服务的cookie设置。如果使用了其他域名的资源,这些不在你的控制范围之内,你需要联系第三方修改他们的cookie设置。 好的,我会修改代码将SameSite设置为None的,这样就万事大吉了,是吗? 很不幸,并不是:Safari存在一个"bug”。这个bug导致Safari不会将None识别为SameSite的合法值。当Safari遇到非法参数值的时候,它会将其视作SameSite=Strict,不会向认证服务发送会话cookie。IOS13和macOS 10.15 Catalina系统上的Safari 13已修复此bug,macOS 10.14 Mojave和iOS 12将不会修复,而这几个版本依旧存在大量用户群。 现在我们进退两难:要么忽略此次更新,Chrome用户无法使用静默刷新,要么设置SameSite=None,那么无法更新到最新系统的iPhone,iPad和Mac用户的应用将出现异常。 有没有方法明确知道自己受影响? 幸运的是,你可以。如果你已经设置了SameSite=None,应该注意到应用在iOS 12,macOS 10.4的Safari上运行异常。如果还没有设置的话,确保要在上面版本系统的Safari上做一下测试。 如果还没有设置的话,可以打开Chrome的开发者工具。可以看到这些警告: A cookie associated with a cross-site resource at {cookie domain} was set without the `SameSite` attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with `SameSite=None` and `Secure`.

IdentityServer4源码解析_8_撤销令牌接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 TO BE UPDATED

IdentityServer4源码解析_7_查询令牌信息接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 TO BE UPDATED

IdentityServer4源码解析_6_结束会话接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 协议简析 会话管理属于可选协议内容,地址如下 https://openid.net/specs/openid-connect-session-1_0.html 认证服务元数据 以下参数必须在元数据中提供 check_session_iframe:必填。在客户端嵌入一个不可见的iframe,地址指向认证服务的checksession地址,使用HTML5的postMessage API互相通讯,客户端向checksession发送请求,认证服务返回用户的登录状态。注意此处属于跨站请求,Cookie的SameSite设置可能影响此处行为 https://localhost:10000/connect/checksession 登出的两种方式 前端登出 客户端在向认证服务注册的时候需要提供frontchannel_logout_uri(前端登出地址)。域名端口和架构必须与redirect_uri一致。 登出地址必须是绝对地址,可以包括application/x-www-form-urlencoded编码的query参数。 认证服务在页面中渲染一个隐藏的iframe,src指向frontchannel_logout_uri。 <iframe src="frontchannel_logout_uri"> 客户端的frontchannel_logout_session_required属性,决定认证服务向客户端发送登出请求的时候是否带上iss和sid参数。 前端登出 - 认证服务发起 如果有多个客户端登入,认证站点会有多个iframe,登出的时候逐个通知。 认证服务元数据中的frontchannel_logout_supported说明是否支持前端登出。frontchannel_logout_session_supported说明登出是否支持传递iss,sid参数。 sid : session id,会话id。 示例: 客户端注册frontchannel_logout_uri为https://rp.example.org/frontchannel_logout,frontchannel_logout_session_required为true,认证服务渲染如下html代码段触发前端登出。 <iframe src="https://rp.example.org/frontchannel_logout ?iss=https://server.example.com &sid=08a5019c-17e1-4977-8f42-65a12843ea02"> </iframe> 前端登出 - 客户端发起 客户端注册的时候提供post_logout_redirect_uris,前端登出后跳转到此地址,此地址只有在客户端发起的登出才会跳转。 详细内容查看协议 后端登出 认证服务发送logout_token到客户端,参数有: iss:必填,签发方 sub:选填,主体标识 aud:必填 iat:必填,签发时间 jtl:必填,token唯一标识 events:必填 sid:选填 示例: { "iss": "https://server.example.com", "sub": "248289761001", "aud": "s6BhdRkqt3", "iat": 1471566154, "jti": "bWJq", "sid": "08a5019c-17e1-4977-8f42-65a12843ea02", "events": { "http://schemas.

IdentityServer4源码解析_5_查询用户信息接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 协议简析 UserInfo接口是OAuth2.0中规定的需要认证访问的接口,可以返回认证用户的声明信息。请求UserInfo接口需要使用通行令牌。响应报文通常是json数据格式,包含了一组claim键值对集合。与UserInfo接口通讯必须使用https。 根据RFC2616协议,UserInfo必须支持GET和POST方法。 UserInfo接口必须接受Bearer令牌。 UserInfo接口应该支持javascript客户端跨域访问,可以使用CORS协议或者其他方案。 UserInfo请求 推荐使用GET方法,使用Authorization头承载Bearer令牌来请求UserInfo接口。 GET /userinfo HTTP/1.1 Host: server.example.com Authorization: Bearer SlAV32hkKG 成功响应 如果某个claim为空或者null,不返回该键。 必须返回sub(subject)声明。 必须校验UserInfo返回的sub与id_token中的sub是否一致 content-type必须是application/json,必须使用utf-8编码 如果加密位jwt返回,content-type必须位application/jwt HTTP/1.1 200 OK Content-Type: application/json { "sub": "248289761001", "name": "Jane Doe", "given_name": "Jane", "family_name": "Doe", "preferred_username": "j.doe", "email": "janedoe@example.com", "picture": "http://example.com/janedoe/me.jpg" } 失败响应 HTTP/1.1 401 Unauthorized WWW-Authenticate: error="invalid_token", error_description="The Access Token expired" 响应校验 客户端必须校验如下内容 校验认证服务身份(https) 如果客户端注册时设置了userinfo_encrypted_response_alg ,收到响应时用对应算法解密 如果响应有签名,客户端需要验签 源码解析 校验通行令牌 首先会尝试从Authorizaton头中获取Bearer Token的值,找到的话则返回 如果content-type为表单类型,尝试从表单中获取access_token参数值 两处都没有获取到Beaer Token的话则返回校验失败结果 public async Task<BearerTokenUsageValidationResult> ValidateAsync(HttpContext context) { var result = ValidateAuthorizationHeader(context); if (result.

IdentityServer4源码解析_4_令牌发放接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 协议 Token接口 oidc服务需要提供token接口,提供AccessToken,IdToken,以及RefreshToken(可选)。在授权码模式下,token接口必须使用https。 请求 必须使用POST方法,使用x-www-form-urlencoded序列化参数,clientId:clientSecret使用Basic加密放在Authorization头中 POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb 请求校验 认证服务必须校验下列内容: 验证client是否颁发了秘钥 验证为该客户端颁发了授权码 验证授权码有效性 如果可能的话,验证授权码是否被使用过 验证redirect_uri 与发起认证请求时的值一致 成功响应 在收到token请求,并校验通过之后,认证服务返回成功报文,报文包含了身份令牌和通行令牌。数据格式使用application/json。token_type必须返回Bearer,其他类型token不在本协议范围内。在OAuth2.0响应报文基础上,oidc增加了id_tken。所有token包含了token或者其他敏感信息的响应报文,必须包含以下响应头。 Cache-Control no-store Pragma no-cache 失败响应 如果认证失败返回application/json格式错误消息,状态码400 HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "error": "invalid_request" } id token校验 客户端必须校验返回的id token, 校验条件如下。对照这些条件,就可以更懂Microsoft.Authentication.OpenIdConnect里面的代码了,要做的事情很多。 如果id token被加密,使用客户端注册时候约定的秘钥和算法解密。如果约定了加密方式,id token未被加密,客户端应该拒绝。 签发方标识必须与iss声明一致 客户端必须校验aud声明包含了它的客户端id,如果id token未返回正确的audience或者反悔了不被新人的audience,应该拒绝 如果id token包含多个audience,需要校验是否有azp声明。azp即Authorized party,标识被授权的client。 如果包含azp声明,客户端需要校验其值是否为自己的客户端id 如果id token由token接口直接颁发给客户端(授权码模式就是如此),客户端必须根据alg参数值的算法验证签名。客户端必须使用签发方提供的秘钥。 alg值默认为RS256,客户端可以在注册的时候使用id_token_signed_response_alg参数指定配置。 如果jwt的alg头使用了基于mac地址的加密算法,如HS256, HS384,HS512,aud声明中的字节会用作验签。(意思是会把mac地址相关信息写在aud声明上?) The current time MUST be before the time represented by the exp Claim.

IdentityServer4源码解析_3_认证接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 协议 五种认证方式 Authorization Code 授权码模式:认证服务返回授权码,后端用clientid和密钥向认证服务证明身份,使用授权码换取id token 和/或 access token。本模式的好处是由后端请求token,不会将敏感信息暴露在浏览器。本模式允许使用refreshToken去维持长时间的登录状态。使用此模式的客户端必须有后端参与,能够保障客户端密钥的安全性。此模式从authorization接口获取授权码,从token接口获取令牌。 Implict 简化模式:校验跳转URI验证客户端身份之后,直接发放token。通常用于纯客户端应用,如单页应用javascript客户端。因为没有后端参与,密钥存放在前端是不安全的。由于安全校验较宽松,本模式不允许使用refreshToken来长时间维持登录状态。本模式的所有token从authorization接口获取。 Hybrid 混合流程:混合流程顾名思义组合使用了授权码模式+简化模式。前端请求授权服务器返回授权码+id_token,这样前端立刻可以使用用户的基本信息;后续请求后端使用授权码+客户端密钥获取access_token。本模式能够使用refreshToken来长时间维持登录状态。使用本模式必须有后端参与保证客户端密钥的安全性。混合模式极少使用,除非你的确需要使用它的某些特性(如一次请求获取授权码和用户资料),一般最常见的还是授权码模式。 Resource Owner Password Credential 用户名密码模式:一般用于无用户交互场景,或者第三方对接(如对接微信登录,实际登录界面就变成了微信的界面,如果不希望让客户扫了微信之后再跑你们系统登录一遍,就可以在后端用此模式静默登录接上自家的sso即可) Client Credential 客户端密钥模式:仅需要约定密钥,仅用于完全信任的内部系统 认证方式特点对比 特点 授权码模式 简化模式 混合模式 所有token从Authorization接口返回 No Yes Yes 所有token从Token接口返回 Yes No No 所有tokens不暴露在浏览器 Yes No No 能够验证客户端密钥 Yes No Yes 能够使用刷新令牌 Yes No Yes 仅需一次请求 No Yes No 大部分请求由后端进行 Yes No 可变 支持返回类型对比 返回类型 认证模式 说明 code Authorization Code Flow 仅返回授权码 id_token Implicit Flow 返回身份令牌 id_token token Implicit Flow 返回身份令牌、通行令牌 code id_token Hybrid Flow 返回授权码、身份令牌 code token Hybrid Flow 返回授权码、通行令牌 code id_token token Hybrid Flow 返回授权码、身份令牌、通行令牌 授权码模式解析 相对来说,授权码模式还是用的最多的,我们详细解读一下本模式的协议内容。

IdentityServer4源码解析_2_元数据接口

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 协议 这一系列我们都采用这样的方式,先大概看下协议,也就是需求描述,然后看idsv4怎么实现的,这样可以加深理解。 元数据接口的协议地址如下: https://openid.net/specs/openid-connect-discovery-1_0.html 摘要 该协议定义了一套标准,用户能够获取到oidc服务的基本信息,包括OAuth2.0相关接口地址。 Webfinger - 网络指纹 先了解一下Webfinger这个概念。 WebFinger可以翻译成网络指纹,它定义了一套标准,描述如何通过标准的HTTP方法去获取网络实体的资料信息。WebFinger使用JSON来描述实体信息。 https://tools.ietf.org/html/rfc7033 查询oidc服务元数据 - OpenID Provider Issuer Discovery 可选协议。 定义了如何获取oidc服务元数据。如果客户端明确知道oidc服务的地址,可以跳过此部分。 个人理解是存在多个oidc服务的情况,可以部署一个webfinger服务,根据资源请求,路由到不同的oidc服务。 通常来说,我们只有一个oidc服务,我看了一下idsv4也没有实现这一部分协议,这里了解一下就可以了。 查询oidc服务配置信息 - OpenID Provider Configuration Request 必选协议。 用于描述oidc服务各接口地址及其他配置信息。 GET /.well-known/openid-configuration HTTP/1.1 Host: example.com 必须校验issuer与请求地址是否一致 启个idsrv服务调用试一下,返回结果如图 详细信息如下。 { "issuer": "https://localhost:10000", //颁发者地址 "jwks_uri": "https://localhost:10000/.well-known/openid-configuration/jwks", //jwks接口地址,查询密钥 "authorization_endpoint": "https://localhost:10000/connect/authorize", //认证接口地址 "token_endpoint": "https://localhost:10000/connect/token", //令牌发放接口 "userinfo_endpoint": "https://localhost:10000/connect/userinfo", //查询用户信息接口 "end_session_endpoint": "https://localhost:10000/connect/endsession", //结束会话接口 "check_session_iframe": "https://localhost:10000/connect/checksession", //检查会话接口 "revocation_endpoint": "https://localhost:10000/connect/revocation", //撤销令牌接口 "introspection_endpoint": "https://localhost:10000/connect/introspect", //查询令牌详情接口 "device_authorization_endpoint": "https://localhost:10000/connect/deviceauthorization", //设备认证接口 "frontchannel_logout_supported": true, //是否支持前端登出 "frontchannel_logout_session_supported": true, //是否支持前端结束会话 "backchannel_logout_supported": true, //是否支持后端登出 "backchannel_logout_session_supported": true, //是否支持后端结束会话 "scopes_supported": [ //支持的授权范围,scope "openid", "profile", "userid", "username", "email", "mobile", "api", "offline_access" //token过期可用refresh_token刷新换取新token ], "claims_supported": [ //支持的声明 "sub", "updated_at", "locale", "zoneinfo", "birthdate", "gender", "preferred_username", "picture", "profile", "nickname", "middle_name", "given_name", "family_name", "website", "name", "userid", "username", "email", "mobile" ], "grant_types_supported": [ //支持的认证类型 "authorization_code", //授权码模式 "client_credentials", //客户端密钥模式 "refresh_token", //刷新token "implicit", //隐式流程, 一般用于单页应用javascript客户端 "password", //用户名密码模式 "urn:ietf:params:oauth:grant-type:device_code" //设备授权码 ], "response_types_supported": [ //支持的返回类型 "code", //授权码 "token", //通行令牌 "id_token", //身份令牌 "id_token token", //身份令牌+统通行令牌 "code id_token", //授权码+身份令牌 "code token", //授权码+通行令牌 "code id_token token" //授权码+身份令牌+通行令牌 ], "response_modes_supported": [ //支持的响应方法 "form_post", //form-post提交 "query", //get提交 "fragment" //fragment提交 ], "token_endpoint_auth_methods_supported": [ //发放令牌接口支持的认证方式 "client_secret_basic", //basic "client_secret_post" //post ], "id_token_signing_alg_values_supported": [ //身份令牌加密算法 "RS256" ], "subject_types_supported": [ "public" ], "code_challenge_methods_supported": [ "plain", "S256" ], "request_parameter_supported": true } JWK - Json Web Keys idsv还注入这样一个接口:DiscoveryKeyEndpoint,尝试发现返回了一组密钥。协议内容如下。

IdentityServer4源码解析_1_项目结构

目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4源码解析_4_令牌发放接口 identityserver4源码解析_5_查询用户信息接口 identityserver4源码解析_6_结束会话接口 identityserver4源码解析_7_查询令牌信息接口 identityserver4源码解析_8_撤销令牌接口 简介 Security源码解析系列介绍了微软提供的各种认证架构,其中OAuth2.0,OpenIdConnect属于远程认证架构,所谓远程认证,是指token的颁发是由其他站点完成的。 IdentityServer4是基于OpenIdConnect协议的认证中心框架,可以帮助我们快速搭建微服务认证中心。 初学者可能看到生涩的概念比较头疼,可以将OAuth, OpenIdConnect协议简单理解成需求文档,idsv4基于需求提供了一系列的api实现。 对于idsv还不太了解的可以看下面的资料,本系列主要学习梳理idsv4的源码,结合协议加深理解。 晓晨姐姐系列文章 https://www.cnblogs.com/stulzq/p/8119928.html 官方文档 https://identityserver4.readthedocs.io/en/latest/ 项目结构 项目地址如下 https://github.com/IdentityServer/IdentityServer4 克隆到本地,项目结构如图 核心项目是IdentityServer4,其余的都是与微软框架集成、以及处理持久化的项目。 项目结构如图。Endpoints文件夹就是接口文件,我们先看下依赖注入、中间件的代码,然后看下每个接口。 依赖注入 public static IIdentityServerBuilder AddIdentityServer(this IServiceCollection services) { var builder = services.AddIdentityServerBuilder(); builder .AddRequiredPlatformServices() .AddCookieAuthentication() .AddCoreServices() .AddDefaultEndpoints() .AddPluggableServices() .AddValidators() .AddResponseGenerators() .AddDefaultSecretParsers() .AddDefaultSecretValidators(); // provide default in-memory implementation, not suitable for most production scenarios builder.AddInMemoryPersistedGrants(); return builder; } AddRequiredPlatformServices - 注入平台服务 IHttpContextAccessor:HttpContext访问器 IdentityServerOptions:配置类 public static IIdentityServerBuilder AddRequiredPlatformServices(this IIdentityServerBuilder builder) { builder.

AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 简介 开篇提到过,认证主要解决的是who are you,授权解决的是 are you allowed的问题。各种认证架构可以帮我们知道用户身份(claims),oauth等架构的scope字段能够控制api服务级别的访问权限,但是更加细化和多变的功能授权不是它们的处理范围。 微软的Authorization项目提供了基于策略的灵活的授权框架。 推荐看下面博客了解,我主要学习和梳理源码。 https://www.cnblogs.com/RainingNight/p/authorization-in-asp-net-core.html 依赖注入 注入了以下接口,提供了默认实现 IAuthorizationService :授权服务,主干服务 IAuthorizationPolicyProvider : 策略提供类 IAuthorizationHandlerProvider:处理器提供类 IAuthorizationEvaluator:校验类 IAuthorizationHandlerContextFactory:授权上下文工厂 IAuthorizationHandler:授权处理器,这个是注入的集合,一个策略可以有多个授权处理器,依次执行 配置类:AuthorizationOptions 微软的命名风格还是比较一致的 Service:服务 Provider:某类的提供者 Evaluator:校验预处理类 Factory:工厂 Handler:处理器 Context:上下文 看源码的过程,不仅可以学习框架背后原理,还可以学习编码风格和设计模式,还是挺有用处的。 /// <summary> /// Adds authorization services to the specified <see cref="IServiceCollection" />. /// </summary> /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param> /// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.

AspNetCore3.1_Secutiry源码解析_7_Authentication_其他

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 简介 Secutiry的认证目录还有这些项目,基本都是具体的OAuth2.0服务商或者其他用的比较少的认证架构,简单看一下,了解一下。 Microsoft.AspNetCore.Authentication.Certificate Microsoft.AspNetCore.Authentication.Facebook Microsoft.AspNetCore.Authentication.Google Microsoft.AspNetCore.Authentication.MicrosoftAccount Microsoft.AspNetCore.Authentication.Negotiate Microsoft.AspNetCore.Authentication.Twitter Microsoft.AspNetCore.Authentication.WsFederation OAuth2.0服务商 Facebook, Google,MicrosoftAccount这几个都可以归为一类,都是OAuth2.0的服务商。国内用的比较多的是QQ,Weixin。我们看一下Facebook的代码,其他的原理都是大同小异的,根据不同厂商的差异稍作调整就可以了。 Twitter似乎是用的OAuth1.0协议。 依赖注入 配置类: FacebookOptions,处理器类:FacebookHandler public static class FacebookAuthenticationOptionsExtensions { public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder) => builder.AddFacebook(FacebookDefaults.AuthenticationScheme, _ => { }); public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, Action<FacebookOptions> configureOptions) => builder.AddFacebook(FacebookDefaults.AuthenticationScheme, configureOptions); public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, Action<FacebookOptions> configureOptions) => builder.AddFacebook(authenticationScheme, FacebookDefaults.DisplayName, configureOptions); public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<FacebookOptions> configureOptions) => builder.

AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 oidc简介 oidc是基于oauth2.0的上层协议。 OAuth有点像卖电影票的,只关心用户能不能进电影院,不关心用户是谁。而oidc则像身份证,扫描就可以上飞机,一次扫描,机场不仅能知道你是否能上飞机,还可以知道你的身份信息。 oidc兼容OAuth2.0, 可以实现跨顶级域的SSO(单点登录、登出),下个系列要学习的IdentityServer4就是对oidc协议族的一个具体实现框架。 更多理论知识看下面的参考资料,本系列主要过下源码脉络 博客园 https://www.cnblogs.com/linianhui/p/openid-connect-core.html 协议 https://openid.net/connect/ 依赖注入 默认架构名称是OpenIdConnect,处理器类是OpenIdConnectHandler,配置类是OpenIdConnectOptions public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder) => builder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, _ => { }); public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, Action<OpenIdConnectOptions> configureOptions) => builder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, configureOptions); public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, Action<OpenIdConnectOptions> configureOptions) => builder.AddOpenIdConnect(authenticationScheme, OpenIdConnectDefaults.DisplayName, configureOptions); public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<OpenIdConnectOptions> configureOptions) { builder.

AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 OAuth简介 现在随便一个网站,不用注册,只用微信扫一扫,然后就可以自动登录,然后第三方网站右上角还出现了你的微信头像和昵称,怎么做到的? sequenceDiagram 用户-x站点: 请求微信登录 x站点-微信: 请求 oauth token 微信-用户: x站点请求基本资料权限,是否同意? 用户-微信: 同意 微信-x站点: token x站点-微信: 请求user基本资料(token) 微信-微信: 校验token 微信-x站点: user基本资料 大概就这么个意思,OAuth可以让第三方获取有限的授权去获取资源。 入门的看博客 https://www.cnblogs.com/linianhui/p/oauth2-authorization.html 英文好有基础的直接看协议 https://tools.ietf.org/html/rfc6749 依赖注入 配置类:OAuthOptions 处理器类: OAuthHandler public static class OAuthExtensions { public static AuthenticationBuilder AddOAuth(this AuthenticationBuilder builder, string authenticationScheme, Action<OAuthOptions> configureOptions) => builder.AddOAuth<OAuthOptions, OAuthHandler<OAuthOptions>>(authenticationScheme, configureOptions); public static AuthenticationBuilder AddOAuth(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<OAuthOptions> configureOptions) => builder.

AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 JwtBear简介 首先回想一下Cookie认证,Cookie认证在用户登录成功之后将用户信息加密后写入浏览器Cookie中,服务端通过解析Cookie内容来验证用户登录状态。这样做有几个缺陷: Cookie加密方式是微软自己定义的,并非国际标准,其他语言无法识别。 依赖Cookie,在跨域场景下,存在诸多限制。 CORS除非设置白名单否则是不允许带Cookie的; 大部分浏览器对跨域设置Cookie有严格的限制。比如:A网站使用iframe嵌套B网站来实现集成,B网站依赖Cookie来维持登录态,如果是Chrome浏览器,需要将Cookie的Secure设置为true,即必须使用https,同时将SameSite设置为None,这样可以解决问题但是存在跨站访问攻击(CSRF)的安全漏洞,而Safari则是完全禁止设置跨站Cookie的) JwtBear可以解决上面的缺点 Jwt是国际标准 Jwt不依赖Cookie,不存在跨站访问攻击问题 依赖注入 提供了四个重载方法,主要设置配置类 JwtBearerOptions。 默认添加名称为Bearer的认证Schema,JwtBearerHandler为处理器类。 public static class JwtBearerExtensions { public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder) => builder.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, _ => { }); public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, Action<JwtBearerOptions> configureOptions) => builder.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, configureOptions); public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, Action<JwtBearerOptions> configureOptions) => builder.

AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 依赖注入 AuthenticationBuilder AddCookie(this AuthenticationBuilder builder); AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme); AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, Action<CookieAuthenticationOptions> configureOptions); 提供了几个重载方法,可以使用默认配置,或者通过委托修改配置类CookieAuthenticationOptions的值。 可以定义登录、登出、拒绝登录页面地址、Cookie过期时间、生命周期各阶段事件等。 classDiagram class CookieAuthenticationOptions{ CookieBuilder Cookie IDataProtectionProvider DataProtectionProvider bool SlidingExpiration PathString LoginPath PathString LogoutPath PathString AccessDeniedPath CookieAuthenticationEvents Events ISecureDataFormat TicketDataFormat ITicketStore SessionStore TimeSpan ExpireTimeSpan } class AuthenticationSchemeOptions{ string ClaimsIssuer object Events Type EventsType string ForwardDefault string ForwardAuthenticate string ForwardChallenge string ForwardForbid string ForwardSignIn string ForwardSignOut Func ForwardDefaultSelector } CookieAuthenticationOptions--AuthenticationSchemeOptions 如果没有定义配置,则会使用CookieAuthenticationDefaults定义的默认配置

AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 依赖注入 框架提供了三个依赖注入重载方法。 //注入认证服务 services.AddAuthentication(); //注入认证服务并制定默认架构名 services.AddAuthentication("Cookies"); //注入认证服务并设置配置项 services.AddAuthentication(config => { }); 看看注入代码 public static AuthenticationBuilder AddAuthentication(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.AddAuthenticationCore(); services.AddDataProtection(); services.AddWebEncoders(); services.TryAddSingleton<ISystemClock, SystemClock>(); return new AuthenticationBuilder(services); } AddAuthenticationCore注入了认证服务的核心对象。这个方法在Authentication.Core项目,这个项目定义了认证服务的核心对象,在Authentication.Abstractions项目中定义了核心接口。 AddAuthenticationCore方法注入了IAuthenticationService,IClaimsTransformation,IAuthenticationHandlerProvider,IAuthenticationSchemeProvider public static IServiceCollection AddAuthenticationCore(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.TryAddScoped<IAuthenticationService, AuthenticationService>(); services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>(); // Can be replaced with scoped ones that use DbContext services.

AspNetCore3.1_Secutiry源码解析_1_目录

目录 AspNetCore3.1_Secutiry源码解析_1_目录 AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程 AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect AspNetCore3.1_Secutiry源码解析_7_Authentication_其他 AspNetCore3.1_Secutiry源码解析_8_Authorization_授权框架 概述 最近一直在学习研究认证授权这一块,从AspNetCore的Security解决方案,到Identity,再到OAuth2.0、OpenIdConnect协议,然后IdentityServer4,这一块的东西十分多而且复杂,可以算是DotNet里最难啃的骨头之一了。计划做个认证授权的系列,藉由分析源码来学习、记录和加深对这一块的理解。 如图是AspNetCore.Security解决方案的项目结构。 可以看到主要有5个解决方案文件夹 Authentication:认证 Authorization:授权 CookiePolicy:Cookie策略中间件 _dependencies:依赖项目 benchmarks:测试项目 最主要的是Authentication和Authorization这两个里面的内容。 什么是Authentication, 什么是Authorization 初次接触这一块,可能会比较懵,啥玩意儿啊,俩单词长得差不多像念绕口令的。 我尝试大白话解释下。 Authentication(认证):who are you。系统获知当前用户身份的过程就叫认证。可以类比成身份证。通常来说,在你登录的时候,系统就知道了你的身份,然后将当前用户信息加密后存储在Cookie中来维持登录态。 Authorization(授权):are you allowed。授权就是判断你有没有权限,比如网管拿着你身份证一看,你这不行,未满十八岁,不能在我这上网。而有的黑网吧是没有这个要求的,给钱就能玩。正经网吧和黑网吧,这就是需要授权资源和匿名资源的区别。 Authentication项目简介 我们可以看到第三个文件夹叫Core,里面只有一个项目叫Microsoft.AspNetCore.Authentication,是我们使用DotNet授权框架必须引用的一个核心类库。 然后其他的Certificate、Cookies、OAuth、OpenIdConnect等这些,在DotNet里叫做Schema,可以翻译为架构。这就好比,证明身份的方式有很多种,身份证、护照、户口本都可以,同理网络世界也有各种各样的协议。最常见传统的是方式是使用Cookie,也可以使用无状态的JwtBear,现在常见的微信、QQ等扫码登录是使用的OAuth协议。 Authorization项目简介 授权就两个项目,[Microsoft.AspNetCore.Authorization.Policy],[Microsoft.AspNetCore.Authorization]。多看看源码的话,应该对Policy这个词很熟悉了,在DotNet里面属于高频词汇,意思是策略。这两个项目允许设置不同的授权策略/规则,来实现高度灵活的授权方案。

AspNetCore3.1_Middleware源码解析_4_StaticFiles

概述 AspNetCore提供了StaticFiles中间件,使我们可以轻松访问静态文件。 使用方法 AspNetCore提供了三个重载方法,没有特殊需求的情况下,我们使用无参的就可以了。 //使用默认配置 app.UseStaticFiles(); //自定义静态资源相对路径 app.UseStaticFiles("/MyCustomStaticFilePath"); //所有可以配置的选项 app.UseStaticFiles(new StaticFileOptions { //用于映射file的content-type ContentTypeProvider = null, //ContentTypeProvider无法决定content-type时的默认content-type DefaultContentType = null, //文件提供程序 FileProvider = new PhysicalFileProvider("/"), //Https请求,ResponseCompression中间件启用的情况下,是否对返回值压缩 HttpsCompression = Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.Compress, //委托,状态码和Headers设置完,Body写入前触发,可用于修改响应头 OnPrepareResponse = null, //映射静态资源的相对路径 RequestPath = "/MyStaticFiles", //是否伺服未知文件类型 ServeUnknownFileTypes = false }); TO BE CONTINUE…

AspNetCore3.1_Middleware源码解析_3_HttpsRedirection

概述 上文提到3.1版本默认没有使用Hsts,但是使用了HttpsRedirection这个中间件。看名字就很好理解,https跳转,顾名思义,就是跳转到https地址。 使用场景:当用户使用http访问网站时,自动跳转到https地址。这样更加安全,也更加方便,因为不需要用户特意输入https://。 具体怎么实现的我们来看看。 app.UseHttpsRedirection(); 使用方法 跟Hsts一样,HttpsRedirection默认是不需要注入的,除非你需要修改默认配置。 services.AddHttpsRedirection(config => { //https地址的端口号,默认null config.HttpsPort = 12345; //跳转响应的状态码,默认307 config.RedirectStatusCode = 302; }); 直接使用中间件即可 app.UseHttpsRedirection(); 源码解析 源代码很简单,只有两个类:HttpsRedirectionOptions配置类,HttpsRedirectionMiddleware中间件 HttpsRedirectionOptions就只有两个配置项 /// <summary> /// Options for the HttpsRedirection middleware /// </summary> public class HttpsRedirectionOptions { /// <summary> /// The status code used for the redirect response. The default is 307. /// </summary> public int RedirectStatusCode { get; set; } = StatusCodes.

AspNetCore3.1_Middleware源码解析_2_Hsts

概述 在DotNetCore2.2版本中,当你新增一个WebAPI项目,Startup.cs文件中,会有这么一行代码(3.1版本默认没有使用该中间件)。 if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } 这段代码,翻译一下就是开发环境使用开发异常页面,其他环境使用Hsts中间件。这个Hsts中间件是个什么东西呢,今天来看一看。 HSTS是什么 HTTP严格传输安全协议(英语:HTTP Strict Transport Security,简称:HSTS)。 简单描述一下协议内容,就是出于安全考虑,强制客户端使用https与服务端连接。 为什么要这么做呢,比较学术和系统的论述自行查看下面的链接。我这里举个通俗的栗子。 首先我们知道http是不安全的,而https是安全的,它能保障你访问的A网站就是A,而不是什么其他的野鸡。 某一天,你去逛淘宝,你往chrome地址栏敲 taobao.com,正常情况下岁月安好,什么问题都没有。假如,这时候你接入的是公共免费wifi,而这背后有人搞鬼,或者说你的电脑已经中了病毒,它可以将你跳转到一个跟taobao一模一样的网站 (怎么做到的?比如修改你的host文件,将taobao域名指向他自己搭建的假taobao网站ip),浏览器并不知道taobao需要使用https访问,所以无法保护你,你的钱就在你的鼠标点击下,跟随着一个个http请求流入到了黑客的账户。 那要怎么办呢,不上公共wifi行不行,行,但是防不胜防,不是根本的办法。 那我们告诉浏览器taobao需要用https访问行不行,听起来不错,那怎么告诉呢,我们来搞个协议,这个协议就是HSTS。 一句话描述HTST:当你首次使用https访问了taobao成功后,taobao会返回Strict-Transport-Security头,表明我这个网站需要使用https访问,浏览器记录下这个信息,以后taobao的请求都会使用https,因此堵住了上面案例的安全漏洞。 https://baike.baidu.com/item/HTTP%E4%B8%A5%E6%A0%BC%E4%BC%A0%E8%BE%93%E5%AE%89%E5%85%A8%E5%8D%8F%E8%AE%AE/16018283?fromtitle=HSTS&fromid=8665782&fr=aladdin https://developer.mozilla.org/zh-CN/docs/Security/HTTP_Strict_Transport_Security https://tools.ietf.org/html/rfc6797 HSTS中间件的使用 通常,我们不需要写Hsts的注入代码,因为它没有任何需要注入的服务。除非你需要修改它的默认配置。 services.AddHsts(config => { //是否包含子域名,默认false config.IncludeSubDomains = true; //有效时长,默认30天 config.MaxAge = TimeSpan.FromDays(365); }); 然后,使用中间件即可。

AspNetCore3.1_Middleware源码解析_1_CORS

概述 什么是跨域 在前后端分离开发方式中,跨域是我们经常会遇到的问题。所谓的跨域,就是出于安全考虑,A域名向B域名发出Ajax请求,浏览器会拒绝,抛出类似下图的错误。 JSONP JSONP不是标准跨域协议,更像是聪明程序员投机取巧的办法。这种方式的原理就是js是没有跨域限制的,你想想你引用bootstrap.js是不是网络地址放进来就可以用了。 实际上,所有src属性都不限制跨域的,比如img标签使用跨域图片是不会有问题的。 过程大体分下面四步。 首先约定数据格式和回调函数名 A网站引用B网站的js B网站用约定好的回调函数将数据包裹起来,在A引用的js里返回 A网站在回调函数中获取数据 这个方案的优点是兼容性比较好,古老版本的IE都可以支持,毕竟只是基于js的一个技巧,并没有新的技术或协议。 缺点比较明显,只支持GET,理解起来比较别扭,调用失败不会返回http状态码,安全性存在一定问题。 CORS CORS的全称是Cross Origin Resource Sharing,翻译过来就是跨域资源共享。 跨域问题本质就是浏览器处于安全考虑,阻止了客户端跨域请求。但说到底,客户端请求安不安全还不是服务端说了算的,服务端都说我们家大米你们随便吃,浏览器还阻止,这不是碍事吗,你个物业还当自己业主啦? 但是浏览器也不能随便放行,毕竟网上冲浪的不仅有正经客人,还有小偷,真出问题了还得吐槽物业稀烂。浏览器说,服务端,这个客户端要去你家吃大米,你得告诉我你同不同意啊,服务端说我咋告诉你啊,我总不能来个人就冲着岗亭喊 I’M OK吧。浏览器说那我们搞个协议吧,整个互联网小区都按这个规范来,你们就按这个格式回复我。 这个协议就是CORS了。 下图描述了简单请求的流程。 graph LR; A(客户端)--B(不带Orgin跨域请求); B--C(浏览器拒绝); A--D(带Origin跨域请求); D--E(服务端返回白名单); E--F(白名单内); E--G(白名单外); F--H(浏览器放行); G--C 关于CORS简单请求,复杂请求,以及详细内容参考下面文章,不再赘述。 http://www.ruanyifeng.com/blog/2016/04/cors.html CORS的缺点就是IE10以下不支持,如果你的项目需要兼容这些浏览器的话需要注意。 怎么实现CORS CORS说白了其实就是在响应头里加东西,你可以在运维环节比如nginx加,可以在代码里加,常见的做法是中间件统一处理。AspNetCore为我们提供了CORS中间件。 AspNetCore_CORS中间件的使用 使用CORS中间件两句代码就够了,在Startup文件中 //注入CORS相关的服务,配置跨域策略 public void ConfigureServices(IServiceCollection services) { //策略1,允许所有域名跨域访问 config.AddPolicy("policy1", policy => { policy.AllowAnyOrigin(). AllowAnyMethod(). AllowAnyOrigin(). AllowAnyMethod(); //注意:AllowAnyOrigin和AllowCredential不能同时出现,否则会报错 //AllowCredential即是否允许客户端发送cookie,基于安全原因,CORS协议规定不允许AllowOrigin为通配符的情况下设置允许发送cookie //.AllowCredentials(); }); //策略2,仅允许特定域名、方法、请求头访问 config.

构建个人博客-2-使用Webhook自动发布

概述 上篇介绍了怎么利用hugo搭建个人博客。 有一个地方还是有点不方便,就是git push之后需要等半个小时才能发布。 所以我想利用github的webhook实现每次推送自动发布。 github设置钩子 所谓的webhook,就是钩子,就是github搞事情的时候就会通知你。所以你需要准备一个接口接收github的post请求。 这里我设置为接收json格式数据,仅push时通知。 编写接口 生产环境一般是使用Travis Ci或者Jenkins来实现类似功能,但这对于我来说有点重型了。所以自己写个接口简单实现下。 需求很简单,每当有代码推送的时候,拉取git并发布到blog部署目录。 我这里使用.net core实现,代码十分简单,其实就一行,执行blog.sh脚本。 再看下这个blog.sh脚本的内容,也很简单,首先拉取git内容,再拷贝到部署目录就行了。 #!/bin/bash cd /git/blog git pull cp -rf /git/blog/public/. /www/wwwroot/www.holdengong.com/ 这里有3个小坑要注意 第一行的 #!/bin/bash 是必须的 脚本必须是ANSI编码 需要执行命令 chmod +x blog.sh 是脚本可执行 完成 大功告成。接下来可以愉快的写日志了,写完只需要签入,自动发布,爽! 这篇博客由系统自动发布

构建个人博客_1_使用Hugo快速成型

概述 人在武汉,病毒肆虐。 隔离久了,有点闷,闲余时间找点事情做。 建个博客吧, 内容不重要,写不写也不那么要紧,目前水平也写不出什么有深度的东西。 但是这个姿势一定要优美, 过程一定要折腾。 OK, 开干。 下载Hugo https://github.com/gohugoio/hugo/releases 笔者是Windows系统,下载hugo_0.67.0_Windows-64bit.zip,解压到本地后,将路径加入到环境变量。 创建站点 首先创建一个git仓库 拉取到本地 如文件夹名为blog cd blog hugo new site . 编写正文 hugo new hello-world.md 下载主题 cd theme git clone https://github.com/spf13/hyde.git 调试 hugo server --theme=hyde --buildDrafts 然后浏览器打开 http://localhost1313 可以查看效果 发布 发布前将hello-world.md的draft字段修改为true, https://holdengong.com/ 为你网站的域名 hugo --theme=hyde -b https://holdengong.com/ 执行完后会发现生成了public文件夹及内容 部署 云服务器可以使用腾讯云的学生版 https://cloud.tencent.com/act/campus?fromSource=gwzcw.2432501.2432501.2432501&utm_medium=cpc&utm_id=gwzcw.2432501.2432501.2432501 安装宝塔面板linux管理工具 https://www.bt.cn/ 安装git yum -y install git 拉取git仓库, e.g.仓库目录为/git/blog 宝塔新建站点 e.g.站点根路由为/www/wwwroot/www.holdengong.com 定时发布 利用linux的定时任务做一个简单的定时发布