Coooooooool

Coooooooool 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织 valine.js.org 编辑
编辑

console.log(x);

个人动态

Coooooooool 收藏了文章 · 3月24日

Token 认证的来龙去脉

不久前,我在在前后端分离实践中提到了基于 Token 的认证,现在我们稍稍深入一些。

通常情况下,我们在讨论某个技术的时候,都是从问题开始。那么第一个问题:

为什么要用 Token?

而要回答这个问题很简单——因为它能解决问题!

可以解决哪些问题呢?

  1. Token 完全由应用管理,所以它可以避开同源策略
  2. Token 可以避免 CSRF 攻击
  3. Token 可以是无状态的,可以在多个服务间共享

Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。

于是,又一个问题产生了:需要为 Token 设置有效期吗?

需要设置有效期吗?

对于这个问题,我们不妨先看两个例子。一个例子是登录密码,一般要求定期改变密码,以防止泄漏,所以密码是有有效期的;另一个例子是安全证书。SSL 安全证书都有有效期,目的是为了解决吊销的问题,对于这个问题的详细情况,来看看知乎的回答。所以无论是从安全的角度考虑,还是从吊销的角度考虑,Token 都需要设有效期。

那么有效期多长合适呢?

只能说,根据系统的安全需要,尽可能的短,但也不能短得离谱——想像一下手机的自动熄屏时间,如果设置为 10 秒钟无操作自动熄屏,再次点亮需要输入密码,会不会疯?如果你觉得不会,那就亲自试一试,设置成可以设置的最短时间,坚持一周就好(不排除有人适应这个时间,毕竟手机厂商也是有用户体验研究的)。

然后新问题产生了,如果用户在正常操作的过程中,Token 过期失效了,要求用户重新登录……用户体验岂不是很糟糕?

为了解决在操作过程不能让用户感到 Token 失效这个问题,有一种方案是在服务器端保存 Token 状态,用户每次操作都会自动刷新(推迟) Token 的过期时间——Session 就是采用这种策略来保持用户登录状态的。然而仍然存在这样一个问题,在前后端分离、单页 App 这些情况下,每秒种可能发起很多次请求,每次都去刷新过期时间会产生非常大的代价。如果 Token 的过期时间被持久化到数据库或文件,代价就更大了。所以通常为了提升效率,减少消耗,会把 Token 的过期时保存在缓存或者内存中。

还有另一种方案,使用 Refresh Token,它可以避免频繁的读写操作。这种方案中,服务端不需要刷新 Token 的过期时间,一旦 Token 过期,就反馈给前端,前端使用 Refresh Token 申请一个全新 Token 继续使用。这种方案中,服务端只需要在客户端请求更新 Token 的时候对 Refresh Token 的有效性进行一次检查,大大减少了更新有效期的操作,也就避免了频繁读写。当然 Refresh Token 也是有有效期的,但是这个有效期就可以长一点了,比如,以天为单位的时间。

时序图表示

使用 Token 和 Refresh Token 的时序图如下:

1)登录

clipboard.png

2)业务请求

clipboard.png

3)Token 过期,刷新 Token

clipboard.png

上面的时序图中并未提到 Refresh Token 过期怎么办。不过很显然,Refresh Token 既然已经过期,就该要求用户重新登录了。

当然还可以把这个机制设计得更复杂一些,比如,Refresh Token 每次使用的时候,都更新它的过期时间,直到与它的创建时间相比,已经超过了非常长的一段时间(比如三个月),这等于是在相当长一段时间内允许 Refresh Token 自动续期。

到目前为止,Token 都是有状态的,即在服务端需要保存并记录相关属性。那说好的无状态呢,怎么实现?

无状态 Token

如果我们把所有状态信息都附加在 Token 上,服务器就可以不保存。但是服务端仍然需要认证 Token 有效。不过只要服务端能确认是自己签发的 Token,而且其信息未被改动过,那就可以认为 Token 有效——“签名”可以作此保证。平时常说的签名都存在一方签发,另一方验证的情况,所以要使用非对称加密算法。但是在这里,签发和验证都是同一方,所以对称加密算法就能达到要求,而对称算法比非对称算法要快得多(可达数十倍差距)。更进一步思考,对称加密算法除了加密,还带有还原加密内容的功能,而这一功能在对 Token 签名时并无必要——既然不需要解密,摘要(散列)算法就会更快。可以指定密码的散列算法,自然是 HMAC。

上面说了这么多,还需要自己去实现吗?不用!JWT 已经定义了详细的规范,而且有各种语言的若干实现。

不过在使用无状态 Token 的时候在服务端会有一些变化,服务端虽然不保存有效的 Token 了,却需要保存未到期却已注销的 Token。如果一个 Token 未到期就被用户主动注销,那么服务器需要保存这个被注销的 Token,以便下次收到使用这个仍在有效期内的 Token 时判其无效。有没有感到一点沮丧?

在前端可控的情况下(比如前端和服务端在同一个项目组内),可以协商:前端一但注销成功,就丢掉本地保存(比如保存在内存、LocalStorage 等)的 Token 和 Refresh Token。基于这样的约定,服务器就可以假设收到的 Token 一定是没注销的(因为注销之后前端就不会再使用了)。

如果前端不可控的情况,仍然可以进行上面的假设,但是这种情况下,需要尽量缩短 Token 的有效期,而且必须在用户主动注销的情况下让 Refresh Token 无效。这个操作存在一定的安全漏洞,因为用户会认为已经注销了,实际上在较短的一段时间内并没有注销。如果应用设计中,这点漏洞并不会造成什么损失,那采用这种策略就是可行的。

在使用无状态 Token 的时候,有两点需要注意:

  1. Refresh Token 有效时间较长,所以它应该在服务器端有状态,以增强安全性,确保用户注销时可控
  2. 应该考虑使用二次认证来增强敏感操作的安全性

到此,关于 Token 的话题似乎差不多了——然而并没有,上面说的只是认证服务和业务服务集成在一起的情况,如果是分离的情况呢?

分离认证服务

当 Token 无状态之后,单点登录就变得容易了。前端拿到一个有效的 Token,它就可以在任何同一体系的服务上认证通过——只要它们使用同样的密钥和算法来认证 Token 的有效性。就样这样:

clipboard.png

当然,如果 Token 过期了,前端仍然需要去认证服务更新 Token:

clipboard.png

可见,虽然认证和业务分离了,实际即并没产生多大的差异。当然,这是建立在认证服务器信任业务服务器的前提下,因为认证服务器产生 Token 的密钥和业务服务器认证 Token 的密钥和算法相同。换句话说,业务服务器同样可以创建有效的 Token。

如果业务服务器不能被信任,该怎么办?

不受信的业务服务器

遇到不受信的业务服务器时,很容易想到的办法是使用不同的密钥。认证服务器使用密钥1签发,业务服务器使用密钥2验证——这是典型非对称加密签名的应用场景。认证服务器自己使用私钥对 Token 签名,公开公钥。信任这个认证服务器的业务服务器保存公钥,用于验证签名。幸好,JWT 不仅可以使用 HMAC 签名,也可以使用 RSA(一种非对称加密算法)签名。

不过,当业务服务器已经不受信任的时候,多个业务服务器之间使用相同的 Token 对用户来说是不安全的。因为任何一个服务器拿到 Token 都可以仿冒用户去另一个服务器处理业务……悲剧随时可能发生。

为了防止这种情况发生,就需要在认证服务器产生 Token 的时候,把使用该 Token 的业务服务器的信息记录在 Token 中,这样当另一个业务服务器拿到这个 Token 的时候,发现它并不是自己应该验证的 Token,就可以直接拒绝。

现在,认证服务器不信任业务服务器,业务服务器相互也不信任,但前端是信任这些服务器的——如果前端不信任,就不会拿 Token 去请求验证。那么为什么会信任?可能是因为这些是同一家公司或者同一个项目中提供的若干服务构成的服务体系。

但是,前端信任不代表用户信任。如果 Token 不没有携带用户隐私(比如姓名),那么用户不会关心信任问题。但如果 Token 含有用户隐私的时候,用户得关心信任问题了。这时候认证服务就不得不再啰嗦一些,当用户请求 Token 的时候,问上一句,你真的要授权给某某某业务服务吗?而这个“某某某”,用户怎么知道它是不是真的“某某某”呢?用户当然不知道,甚至认证服务也不知道,因为公钥已经公开了,任何一个业务都可以声明自己是“某某某”。

为了得到用户的信任,认证服务就不得不帮助用户来甄别业务服务。所以,认证服器决定不公开公钥,而是要求业务服务先申请注册并通过审核。只有通过审核的业务服务器才能得到认证服务为它创建的,仅供它使用的公钥。如果该业务服务泄漏公钥带来风险,由该业务服务自行承担。现在认证服务可以清楚的告诉用户,“某某某”服务是什么了。如果用户还是不够信任,认证服务甚至可以问,某某某业务服务需要请求 A、B、C 三项个人数据,其中 A 是必须的,不然它不工作,是否允许授权?如果你授权,我就把你授权的几项数据加密放在 Token 中……

废话了这么多,有没有似曾相识……对了,这类似开放式 API 的认证过程。开发式 API 多采用 OAuth 认证,而关于 OAuth 的探讨资源非常丰富,这里就不深究了。

查看原文

Coooooooool 赞了文章 · 3月24日

Token 认证的来龙去脉

不久前,我在在前后端分离实践中提到了基于 Token 的认证,现在我们稍稍深入一些。

通常情况下,我们在讨论某个技术的时候,都是从问题开始。那么第一个问题:

为什么要用 Token?

而要回答这个问题很简单——因为它能解决问题!

可以解决哪些问题呢?

  1. Token 完全由应用管理,所以它可以避开同源策略
  2. Token 可以避免 CSRF 攻击
  3. Token 可以是无状态的,可以在多个服务间共享

Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。

于是,又一个问题产生了:需要为 Token 设置有效期吗?

需要设置有效期吗?

对于这个问题,我们不妨先看两个例子。一个例子是登录密码,一般要求定期改变密码,以防止泄漏,所以密码是有有效期的;另一个例子是安全证书。SSL 安全证书都有有效期,目的是为了解决吊销的问题,对于这个问题的详细情况,来看看知乎的回答。所以无论是从安全的角度考虑,还是从吊销的角度考虑,Token 都需要设有效期。

那么有效期多长合适呢?

只能说,根据系统的安全需要,尽可能的短,但也不能短得离谱——想像一下手机的自动熄屏时间,如果设置为 10 秒钟无操作自动熄屏,再次点亮需要输入密码,会不会疯?如果你觉得不会,那就亲自试一试,设置成可以设置的最短时间,坚持一周就好(不排除有人适应这个时间,毕竟手机厂商也是有用户体验研究的)。

然后新问题产生了,如果用户在正常操作的过程中,Token 过期失效了,要求用户重新登录……用户体验岂不是很糟糕?

为了解决在操作过程不能让用户感到 Token 失效这个问题,有一种方案是在服务器端保存 Token 状态,用户每次操作都会自动刷新(推迟) Token 的过期时间——Session 就是采用这种策略来保持用户登录状态的。然而仍然存在这样一个问题,在前后端分离、单页 App 这些情况下,每秒种可能发起很多次请求,每次都去刷新过期时间会产生非常大的代价。如果 Token 的过期时间被持久化到数据库或文件,代价就更大了。所以通常为了提升效率,减少消耗,会把 Token 的过期时保存在缓存或者内存中。

还有另一种方案,使用 Refresh Token,它可以避免频繁的读写操作。这种方案中,服务端不需要刷新 Token 的过期时间,一旦 Token 过期,就反馈给前端,前端使用 Refresh Token 申请一个全新 Token 继续使用。这种方案中,服务端只需要在客户端请求更新 Token 的时候对 Refresh Token 的有效性进行一次检查,大大减少了更新有效期的操作,也就避免了频繁读写。当然 Refresh Token 也是有有效期的,但是这个有效期就可以长一点了,比如,以天为单位的时间。

时序图表示

使用 Token 和 Refresh Token 的时序图如下:

1)登录

clipboard.png

2)业务请求

clipboard.png

3)Token 过期,刷新 Token

clipboard.png

上面的时序图中并未提到 Refresh Token 过期怎么办。不过很显然,Refresh Token 既然已经过期,就该要求用户重新登录了。

当然还可以把这个机制设计得更复杂一些,比如,Refresh Token 每次使用的时候,都更新它的过期时间,直到与它的创建时间相比,已经超过了非常长的一段时间(比如三个月),这等于是在相当长一段时间内允许 Refresh Token 自动续期。

到目前为止,Token 都是有状态的,即在服务端需要保存并记录相关属性。那说好的无状态呢,怎么实现?

无状态 Token

如果我们把所有状态信息都附加在 Token 上,服务器就可以不保存。但是服务端仍然需要认证 Token 有效。不过只要服务端能确认是自己签发的 Token,而且其信息未被改动过,那就可以认为 Token 有效——“签名”可以作此保证。平时常说的签名都存在一方签发,另一方验证的情况,所以要使用非对称加密算法。但是在这里,签发和验证都是同一方,所以对称加密算法就能达到要求,而对称算法比非对称算法要快得多(可达数十倍差距)。更进一步思考,对称加密算法除了加密,还带有还原加密内容的功能,而这一功能在对 Token 签名时并无必要——既然不需要解密,摘要(散列)算法就会更快。可以指定密码的散列算法,自然是 HMAC。

上面说了这么多,还需要自己去实现吗?不用!JWT 已经定义了详细的规范,而且有各种语言的若干实现。

不过在使用无状态 Token 的时候在服务端会有一些变化,服务端虽然不保存有效的 Token 了,却需要保存未到期却已注销的 Token。如果一个 Token 未到期就被用户主动注销,那么服务器需要保存这个被注销的 Token,以便下次收到使用这个仍在有效期内的 Token 时判其无效。有没有感到一点沮丧?

在前端可控的情况下(比如前端和服务端在同一个项目组内),可以协商:前端一但注销成功,就丢掉本地保存(比如保存在内存、LocalStorage 等)的 Token 和 Refresh Token。基于这样的约定,服务器就可以假设收到的 Token 一定是没注销的(因为注销之后前端就不会再使用了)。

如果前端不可控的情况,仍然可以进行上面的假设,但是这种情况下,需要尽量缩短 Token 的有效期,而且必须在用户主动注销的情况下让 Refresh Token 无效。这个操作存在一定的安全漏洞,因为用户会认为已经注销了,实际上在较短的一段时间内并没有注销。如果应用设计中,这点漏洞并不会造成什么损失,那采用这种策略就是可行的。

在使用无状态 Token 的时候,有两点需要注意:

  1. Refresh Token 有效时间较长,所以它应该在服务器端有状态,以增强安全性,确保用户注销时可控
  2. 应该考虑使用二次认证来增强敏感操作的安全性

到此,关于 Token 的话题似乎差不多了——然而并没有,上面说的只是认证服务和业务服务集成在一起的情况,如果是分离的情况呢?

分离认证服务

当 Token 无状态之后,单点登录就变得容易了。前端拿到一个有效的 Token,它就可以在任何同一体系的服务上认证通过——只要它们使用同样的密钥和算法来认证 Token 的有效性。就样这样:

clipboard.png

当然,如果 Token 过期了,前端仍然需要去认证服务更新 Token:

clipboard.png

可见,虽然认证和业务分离了,实际即并没产生多大的差异。当然,这是建立在认证服务器信任业务服务器的前提下,因为认证服务器产生 Token 的密钥和业务服务器认证 Token 的密钥和算法相同。换句话说,业务服务器同样可以创建有效的 Token。

如果业务服务器不能被信任,该怎么办?

不受信的业务服务器

遇到不受信的业务服务器时,很容易想到的办法是使用不同的密钥。认证服务器使用密钥1签发,业务服务器使用密钥2验证——这是典型非对称加密签名的应用场景。认证服务器自己使用私钥对 Token 签名,公开公钥。信任这个认证服务器的业务服务器保存公钥,用于验证签名。幸好,JWT 不仅可以使用 HMAC 签名,也可以使用 RSA(一种非对称加密算法)签名。

不过,当业务服务器已经不受信任的时候,多个业务服务器之间使用相同的 Token 对用户来说是不安全的。因为任何一个服务器拿到 Token 都可以仿冒用户去另一个服务器处理业务……悲剧随时可能发生。

为了防止这种情况发生,就需要在认证服务器产生 Token 的时候,把使用该 Token 的业务服务器的信息记录在 Token 中,这样当另一个业务服务器拿到这个 Token 的时候,发现它并不是自己应该验证的 Token,就可以直接拒绝。

现在,认证服务器不信任业务服务器,业务服务器相互也不信任,但前端是信任这些服务器的——如果前端不信任,就不会拿 Token 去请求验证。那么为什么会信任?可能是因为这些是同一家公司或者同一个项目中提供的若干服务构成的服务体系。

但是,前端信任不代表用户信任。如果 Token 不没有携带用户隐私(比如姓名),那么用户不会关心信任问题。但如果 Token 含有用户隐私的时候,用户得关心信任问题了。这时候认证服务就不得不再啰嗦一些,当用户请求 Token 的时候,问上一句,你真的要授权给某某某业务服务吗?而这个“某某某”,用户怎么知道它是不是真的“某某某”呢?用户当然不知道,甚至认证服务也不知道,因为公钥已经公开了,任何一个业务都可以声明自己是“某某某”。

为了得到用户的信任,认证服务就不得不帮助用户来甄别业务服务。所以,认证服器决定不公开公钥,而是要求业务服务先申请注册并通过审核。只有通过审核的业务服务器才能得到认证服务为它创建的,仅供它使用的公钥。如果该业务服务泄漏公钥带来风险,由该业务服务自行承担。现在认证服务可以清楚的告诉用户,“某某某”服务是什么了。如果用户还是不够信任,认证服务甚至可以问,某某某业务服务需要请求 A、B、C 三项个人数据,其中 A 是必须的,不然它不工作,是否允许授权?如果你授权,我就把你授权的几项数据加密放在 Token 中……

废话了这么多,有没有似曾相识……对了,这类似开放式 API 的认证过程。开发式 API 多采用 OAuth 认证,而关于 OAuth 的探讨资源非常丰富,这里就不深究了。

查看原文

赞 305 收藏 1066 评论 78

Coooooooool 关注了标签 · 2019-12-10

redis

REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。Redis提供了一些丰富的数据结构,包括 lists, sets, ordered sets 以及 hashes ,当然还有和Memcached一样的 strings结构.Redis当然还包括了对这些数据结构的丰富操作。

推荐NoSQL“ FanRedis资料汇总专题

关注 10847

Coooooooool 赞了文章 · 2019-05-28

VsCode从零开始配置一个属于自己的Vue开发环境

原文地址:https://liubing.me/vscode-vue...

VsCode算是比较热门的一个代码编辑器了,全名Visual Studio Code,微软出品,下载地址:点我去下载
插件众多,功能齐全,平常开发过程中都是用的它,整理了下日常使用的插件及配置供大家参考,废话就不多说了,直接进入正题。

相关插件

Vetur

插件文档地址:https://marketplace.visualstudio.com/items?itemName=octref.vetur
Vetur不用说了吧,开发Vue必装的一个插件
未安装之前vue文件显示这样的
image.png
安装完成后显示这样的,看着舒服多了
image.png

Vue 2 Snippets

插件文档地址:https://marketplace.visualstudio.com/items?itemName=hollowtree.vue-snippets
主要加强vue的便捷写法
demo1.gif

demo2.gif

language-stylus

插件文档地址:https://marketplace.visualstudio.com/items?itemName=sysoev.language-stylus
写stylus用的,如果项目用的stylus写样式推荐安装,其他Sass、LESS等同理安装相应的插件即可。

Auto Close Tag

插件文档地址:https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag
自动闭合标签所用
demo3.gif
配合快捷键Alt+. (Command+Alt+. for Mac)特别好使。
demo4.gif

Auto Rename Tag

插件文档地址:https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag
自动修改重命名配对的标签

Bookmarks

插件文档地址:https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks
可以对成片的代码做一些书签标记,方便后续查看。
demo5.gif

Bracket Pair Colorizer

插件文档地址:https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer
对括号进行着色,方便区分,下面的图分别是安装前后的比较
image.png

image.png

Copy Relative Path

插件文档地址:https://marketplace.visualstudio.com/items?itemName=alexdima.copy-relative-path
用于复制文件的完整路径和相对路径,有时候我们可能需要复制一些文件的路径,该插件就很方便了。
demo6.gif

Path Intellisense

插件文档地址:https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense
路径自动感知,在配置文件中配置@后我们就可以很方便快捷的引用各种文件了

"path-intellisense.mappings": {
    "@": "${workspaceRoot}/src"
}

demo7.gif

Document This

插件文档地址:https://marketplace.visualstudio.com/items?itemName=joelday.docthis
主要用于方法的注释,选中方法名,按住Ctrl+Alt后按两次D,即可快速生成标准的注释
demo8.gif

psioniq File Header

插件文档地址:https://marketplace.visualstudio.com/items?itemName=psioniq.psi-header
按住Ctrl+Alt后按两次H既可快速在文件的头部生成注释信息,如果对默认的注释模板不满意的话,可以在配置文件中自定义注释模板

"psi-header.templates": [
  {
    "language": "*",
    "template": [
      "FileName: <<filename>>",
      "Remark: <<filename>>",
      "Project: <<projectname>>",
      "Author: <<author>>",
      "File Created: <<filecreated('dddd, Do MMMM YYYY h:mm:ss a')>>",
      "Last Modified: <<dateformat('dddd, Do MMMM YYYY h:mm:ss a')>>",
      "Modified By: <<author>>"
    ]
  }
]

demo9.gif

demo10.gif

Vue Peek

插件文档地址:https://marketplace.visualstudio.com/items?itemName=dariofuzinato.vue-peek
用于Vue快速查看组件定义以及组件跳转,具体使用见插件文档地址中的使用方法。
demo11.gif

JavaScript (ES6) code snippets

插件文档地址:https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets
用于快速生成ES6代码片段
demo12.gif

Material Icon Theme

插件文档地址:https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme
Material风格的icon文件图标,可以看下安装前后的区别。
image.pngimage.png

ESLint

插件文档地址:https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
这个不用多说了,规范代码格式的。

StandardJS - JavaScript Standard Style

插件文档地址:https://marketplace.visualstudio.com/items?itemName=chenxsan.vscode-standardjs
作为一个合格的前端开发,得遵循一定得代码规范,这里推荐StandardJS,配合该插件可以自动将你的代码格式化成规范的代码。

vue-cli-3脚手架创建项目的时候,可以选择这个规范。

demo13.gif

Beautify

插件文档地址:https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify
主要拿它来格式话html的,也可以格式话vue`template中的html<br />配合vetur插件,需要做些设置,格式化html支持以下四种模式auto|force|force-aligned|force-expand-multiline`

"vetur.format.defaultFormatterOptions": {
  //beautify设置
  "js-beautify-html": {
    "wrap_attributes_indent_size": 2,
      "wrap_attributes": "force-expand-multiline" // auto|force|force-aligned|force-expand-multiline
  }
}

auto模式

image.png

force模式

demo15.gif

force-aligned模式

demo16.gif

force-expand-multiline模式

demo17.gif

vscode-element-helper

插件文档地址:https://marketplace.visualstudio.com/items?itemName=ElemeFE.vscode-element-helper
用element-ui的,应该都知道这个插件,功能看图就知道了。

Version Lens

插件文档地址:https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens
显示npm,jspm,bower,dub和dotnet核心的软件包版本信息

image.png

One Dark Pro

插件文档地址:https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme
一款热门的主题,安装前后比较。
image.png

image.png

相关配置

{
    // 编辑器默认设置
    "editor.tabSize": 2, // 设置2个空格统一tabSize
    "javascript.validate.enable": false, // 关闭默认的校验
    "workbench.editor.enablePreview": false, // 关闭文件预览
    // 引用路径设置
    "path-intellisense.mappings": {
        "@": "${workspaceRoot}/src",
        "~": "${workspaceRoot}/src",
        "src": "${workspaceRoot}/src"
    },
    // standard自动保存
    "standard.autoFixOnSave": true,
    // psioniq File Header设置
    "psi-header.templates": [{
        "language": "*",
        "template": [
            "FileName: <<filename>>",
            "Remark: <<filename>>",
            "Project: <<projectname>>",
            "Author: <<author>>",
            "File Created: <<filecreated('dddd, Do MMMM YYYY h:mm:ss a')>>",
            "Last Modified: <<dateformat('dddd, Do MMMM YYYY h:mm:ss a')>>",
            "Modified By: <<author>>"
        ]
    }],
    // vetur设置
    "vetur.format.defaultFormatter.html": "js-beautify-html",
    "vetur.format.defaultFormatter.js": "none",
    "vetur.format.defaultFormatterOptions": {
        //beautify设置
        "js-beautify-html": {
            "wrap_attributes_indent_size": 2,
            "wrap_attributes": "force-expand-multiline" // auto|force|force-aligned|force-expand-multiline
        }
    },
    // eslint设置
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        {
            "language": "vue",
            "autoFix": true
        }
    ],
    // 保存后自动格式化
    "eslint.autoFixOnSave": true,
    "editor.formatOnSave": true,

    "workbench.iconTheme": "material-icon-theme", // icon图标
    "workbench.colorTheme": "One Dark Pro" // 编辑器主题
}

备份及同步

忙活半天把上面的插件都装上及配置好,下次换新电脑的时候总不能重新再来一遍吧,所以压轴插件登场
Settings Sync
插件文档地址:https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync
安装完成后需要做些其他事情:

创建GitHub Gist ID

点我去创建
image.png
创建完成后有个提示,一定要将红色框所示的token记录下来,不然下次就看不到了。
image.png

上传设置

Shift + Alt + U,会出现一个出入token的框,将上面我们创建的token输入后回车。
image.png
完成后会给你生成一个GIST ID,将这个GIST ID记录下来,下次需要在其他电脑上恢复数据的时候需要用到。
image.png

完整步骤Gif

下载设置

Shift + Alt + D,它将询问您的GitHub Gist ID(我们在步骤创建GitHub Gist ID中生成的一个ID)
在窗口中输入该GitHub Gist ID,然后回车。

提示需要输入您的Gist ID(上面上传设置后生成的一个ID)

下载可能会需要点时间,完整过程Gif

插件配置

最后可以按照自己的需求配置自动上传与自动下载

"sync.autoDownload": false,// 是否自动下载
"sync.autoUpload": false// 是否自动上传

结语

至此教程就结束了,后面有其他问题或者有用的插件会补充进去。

查看原文

赞 200 收藏 158 评论 8

Coooooooool 收藏了文章 · 2019-04-21

svg波浪动画

之前做过CSS动画、canvas动画,但svg动画第一次做,最终效果如下图所示。
图片描述

分析

由上图可以看出,波浪动画是由多个不同的‘波浪’组成,而每个波浪则是由近似正弦图形组成,最后的‘波动’效果,其实是静态的波浪循环向左运动产生的。

同时介绍后面会用到的几个svg相关标签:

  • path:定义形状的基础元素,其中d属性就是图形的路径。静态的波浪就是这个元素绘制的,后面会再单独介绍

  • animateTransform:定义目标元素的变形属性,波浪的循环移动就是使用这个属性实现的

  • g:组合对象的容器

绘制单个静态波浪

 <svg
    xmlns="http://www.w3.org/2000/svg"         
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <path
        d="
            M0 70
            Q 75 39, 150 70
            T 300 70 
            V 100 H 0 V 0"
        fill="#ccc">
    </path>
</svg> 

上面是写好的单个波浪,其中d属性绘制了形状,fill属性表示填充的颜色。

d属性中使用了以下几个命令:

M:M x y表示移动到(x, y)点( svg中左上角是(0,0)点 )
Q:Q x1 y1, x2 y2表示绘制二次贝塞尔曲线,x1 y1为二次贝塞尔的控制点,x2 y2为终点,可以使用贝塞尔生产曲线工具帮助生成。
T:T x y表示生成上一个二次贝塞尔曲线的镜像,其终点坐标为(x,y)
V:V y表示从当前点(x0,y0)垂直移动到(x0, y)
H:H x表示从当前点(x0, y0)水平移动到(x, y0)

所以上面代码可以翻译后为:首先移动到(0,70)处,再绘制起点为(0,70),终点为(150,70),控制点为(75,39)的二次贝塞尔曲线,接着绘制已(300,70)为终点的镜像二次贝塞尔曲线,最后依次移动到(100,70),(0,70),(0,0),从而形成闭合曲线。

动起来

<svg
    xmlns="http://www.w3.org/2000/svg"     
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="300"
    height="200">
    <g >
        <path
            d="M 0 70 Q 75 39, 150 70 T 300 70 T 450 70 T 600 70 T 750 70 V 100 H 0 V 0"
            fill="#ccc">
        </path>
        <animateTransform
            attributeName="transform"
            attributeType="XML"
            type="translate"
            from="0" to="-300" dur="1.5s" 
            repeatCount="indefinite">
        </animateTransform>
    </g>
</svg> 

增加了animateTransform后就动其来了,该标签的几个属性含义为:

attributeName:需要运动的属性
type:具体运动的类型
from:运动初始值
to:运动终点值
dur:运动时间
repeatCount:重复次数,indefinite为无限循环

看了后就发现其实很简单,有一下几个点需要注意,首先path绘制图形的路径至少是svg宽加上from-to的宽,第二,to的值为周期的n/2倍,这个可以想象一下正弦的波形。注意了这两点,波浪看起来已经有点模样了。

多个波浪合成

只有一个波浪,看起来还是不够逼真,将多个不同周期波浪合成,并填充不同透明度的颜色形成最终效果。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="200">
    <g fill="rgba(106,127,239,0.1)">
        <path d="M 0 70 Q 75 39, 150 70 T 300 70 T 450 70 T 600 70 T 750 70 V 100 H 0 V 0"></path>
        <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-300" dur="1.5s" repeatCount="indefinite"></animateTransform>
    </g>
    <g fill="rgba(106,127,239,0.15)">
        <path d="M 0 70 Q 87.5 47, 175 70 T 350 70 T 525 70 T 700 70 T 875 70 T 1050 70 V 100 H 0 V 0"></path>
        <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-350" dur="3s" repeatCount="indefinite"></animateTransform>
    </g>
    <g fill="rgba(106,127,239,0.18)" transform="translate(-903.868 0)">
        <path d="M 0 70 Q 135 36, 270 70 T 540 70 T 810 70 T 1080 70 V 100 H 0 V 0" transform="translate(-38.232284367796474, 0)"></path>
        <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-540" dur="2s" repeatCount="indefinite"></animateTransform>
    </g>
</svg> 

抽象成组件

当手写两个波浪之后,就会发现很多地方是相同的,总结之后会发现只有svg的宽高、周期、峰值、移动速度、初始偏移量(即正弦的初相位)、填充颜色、叠加波浪个数这几个是变化的,因此可以做成组件,隐藏内部的复杂度。

查看原文

Coooooooool 赞了文章 · 2019-04-21

svg波浪动画

之前做过CSS动画、canvas动画,但svg动画第一次做,最终效果如下图所示。
图片描述

分析

由上图可以看出,波浪动画是由多个不同的‘波浪’组成,而每个波浪则是由近似正弦图形组成,最后的‘波动’效果,其实是静态的波浪循环向左运动产生的。

同时介绍后面会用到的几个svg相关标签:

  • path:定义形状的基础元素,其中d属性就是图形的路径。静态的波浪就是这个元素绘制的,后面会再单独介绍

  • animateTransform:定义目标元素的变形属性,波浪的循环移动就是使用这个属性实现的

  • g:组合对象的容器

绘制单个静态波浪

 <svg
    xmlns="http://www.w3.org/2000/svg"         
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <path
        d="
            M0 70
            Q 75 39, 150 70
            T 300 70 
            V 100 H 0 V 0"
        fill="#ccc">
    </path>
</svg> 

上面是写好的单个波浪,其中d属性绘制了形状,fill属性表示填充的颜色。

d属性中使用了以下几个命令:

M:M x y表示移动到(x, y)点( svg中左上角是(0,0)点 )
Q:Q x1 y1, x2 y2表示绘制二次贝塞尔曲线,x1 y1为二次贝塞尔的控制点,x2 y2为终点,可以使用贝塞尔生产曲线工具帮助生成。
T:T x y表示生成上一个二次贝塞尔曲线的镜像,其终点坐标为(x,y)
V:V y表示从当前点(x0,y0)垂直移动到(x0, y)
H:H x表示从当前点(x0, y0)水平移动到(x, y0)

所以上面代码可以翻译后为:首先移动到(0,70)处,再绘制起点为(0,70),终点为(150,70),控制点为(75,39)的二次贝塞尔曲线,接着绘制已(300,70)为终点的镜像二次贝塞尔曲线,最后依次移动到(100,70),(0,70),(0,0),从而形成闭合曲线。

动起来

<svg
    xmlns="http://www.w3.org/2000/svg"     
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="300"
    height="200">
    <g >
        <path
            d="M 0 70 Q 75 39, 150 70 T 300 70 T 450 70 T 600 70 T 750 70 V 100 H 0 V 0"
            fill="#ccc">
        </path>
        <animateTransform
            attributeName="transform"
            attributeType="XML"
            type="translate"
            from="0" to="-300" dur="1.5s" 
            repeatCount="indefinite">
        </animateTransform>
    </g>
</svg> 

增加了animateTransform后就动其来了,该标签的几个属性含义为:

attributeName:需要运动的属性
type:具体运动的类型
from:运动初始值
to:运动终点值
dur:运动时间
repeatCount:重复次数,indefinite为无限循环

看了后就发现其实很简单,有一下几个点需要注意,首先path绘制图形的路径至少是svg宽加上from-to的宽,第二,to的值为周期的n/2倍,这个可以想象一下正弦的波形。注意了这两点,波浪看起来已经有点模样了。

多个波浪合成

只有一个波浪,看起来还是不够逼真,将多个不同周期波浪合成,并填充不同透明度的颜色形成最终效果。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="200">
    <g fill="rgba(106,127,239,0.1)">
        <path d="M 0 70 Q 75 39, 150 70 T 300 70 T 450 70 T 600 70 T 750 70 V 100 H 0 V 0"></path>
        <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-300" dur="1.5s" repeatCount="indefinite"></animateTransform>
    </g>
    <g fill="rgba(106,127,239,0.15)">
        <path d="M 0 70 Q 87.5 47, 175 70 T 350 70 T 525 70 T 700 70 T 875 70 T 1050 70 V 100 H 0 V 0"></path>
        <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-350" dur="3s" repeatCount="indefinite"></animateTransform>
    </g>
    <g fill="rgba(106,127,239,0.18)" transform="translate(-903.868 0)">
        <path d="M 0 70 Q 135 36, 270 70 T 540 70 T 810 70 T 1080 70 V 100 H 0 V 0" transform="translate(-38.232284367796474, 0)"></path>
        <animateTransform attributeName="transform" attributeType="XML" type="translate" from="0" to="-540" dur="2s" repeatCount="indefinite"></animateTransform>
    </g>
</svg> 

抽象成组件

当手写两个波浪之后,就会发现很多地方是相同的,总结之后会发现只有svg的宽高、周期、峰值、移动速度、初始偏移量(即正弦的初相位)、填充颜色、叠加波浪个数这几个是变化的,因此可以做成组件,隐藏内部的复杂度。

查看原文

赞 9 收藏 24 评论 0

Coooooooool 关注了专栏 · 2019-04-21

前端

暂时没有介绍

关注 2

Coooooooool 收藏了文章 · 2018-07-13

小程序:随时随地获取 GitHub 热门项目榜单

最近做了一个很简单的微信小程序:GitHub Trending,很适合用于在做地铁、吃饭等零碎时间场景下去了解最新的 GitHub 热门项目,发现好项目。

项目地址

本项目完全开源,GitHub 地址 :https://github.com/jae-jae/weapp-github-trending

截图



技术栈

  • Min Cli: 小程序开发框架,类 VUE
  • MinUI: 小程序 UI 组件库
  • es6-promise:提供 Promise 支持
  • wx-promise-request:小程序异步网络请求
  • wemark: 小程序 Markdown 渲染库
  • Material Icons: 提供图标支持
  • Yarn || Npm: 包管理
  • Webpack、Babel: 打包构建
  • ES6: JS 语法
  • LESS:CSS 预处理语言
  • GitHub API、QueryList: 提供数据支持

体验

查看原文

Coooooooool 赞了文章 · 2018-07-13

小程序:随时随地获取 GitHub 热门项目榜单

最近做了一个很简单的微信小程序:GitHub Trending,很适合用于在做地铁、吃饭等零碎时间场景下去了解最新的 GitHub 热门项目,发现好项目。

项目地址

本项目完全开源,GitHub 地址 :https://github.com/jae-jae/weapp-github-trending

截图



技术栈

  • Min Cli: 小程序开发框架,类 VUE
  • MinUI: 小程序 UI 组件库
  • es6-promise:提供 Promise 支持
  • wx-promise-request:小程序异步网络请求
  • wemark: 小程序 Markdown 渲染库
  • Material Icons: 提供图标支持
  • Yarn || Npm: 包管理
  • Webpack、Babel: 打包构建
  • ES6: JS 语法
  • LESS:CSS 预处理语言
  • GitHub API、QueryList: 提供数据支持

体验

查看原文

赞 41 收藏 29 评论 2

Coooooooool 关注了专栏 · 2018-07-13

前端每日实战

?该专栏由《CSS3 艺术》一书的作者亲自维护,已累计分享 170+ 个前端项目从灵感闪现到代码实现的完整过程。?

关注 5280

认证与成就

  • 获得 85 次点赞
  • 获得 10 枚徽章 获得 1 枚金徽章, 获得 3 枚银徽章, 获得 6 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2013-12-16
个人主页被 1.4k 人浏览