We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
因为做的项目涉及到用户认证和授权,所以好好总结了一下这块。
一般我们说的认证主要指的是用户登录认证;一般我们说的授权主要是第三方授权。
用户登录认证主要有2种方法,一种是基于session-id的认证,另一种是基于token的认证。
第三方授权主要是Oauth2.0标准的授权,它主要包括授权码模式的授权和简单模式的授权。
基于session-id的认证是比较传统的认证方式,它包含以下几个步骤:
对于这种方式,我们前端的处理方式是:
需要注意的是,上面所有的一切都由服务器来完成,前端只请求接口就行了。服务器能够自己把会话id写入到浏览器的cookie里面。但是对于restful api,服务器是无状态的,所以在第2步需要前端手动把会话id储存在cookie里面,在第4步需要前端手动把会话id从cookie里面删除。
基于token的认证主要是指json web token认证,即jwt认证。
它主要包含如下几个步骤:
需要注意的是,jwt认证有一个很重要的特点:服务器端没有储存token。
为什么服务器端不需要储存token呢,我们来看一下token的生成过程。
jwt这个字符串是由三部分组成:header(头部),payload(主体信息),signature(签名)。
头部是给JWT的基本信息,然后通过加密(base64加密)得到的。通过解密可以得到原始信息。比如下面这段基本信息:类型是jwt,签名算法是HS256。
{ "typ": "JWT", "alg": "HS256" }
加密后的头部如下:
ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9
主体信息是描述用户的信息,然后通过加密(base64加密)得到的。通过解密可以得到原始信息。比如下面这段主体信息。
{ "iss": "Yang JWT", "iat": 1441593502, "exp": 1441594722, "aud": "www.example.com", "sub": "yang@example.com", "from_user": "B", "target_user": "A" }
加密后的主体信息如下:
ew0KICAgICJpc3MiOiAiWWFuZyBKV1QiLA0KICAgICJpYXQiOiAxNDQxNTkzNTAyLA0KICAgICJleHAiOiAxNDQxNTk0NzIyLA0KICAgICJhdWQiOiAid3d3LmV4YW1wbGUuY29tIiwNCiAgICAic3ViIjogInlhbmdAZXhhbXBsZS5jb20iLA0KICAgICJmcm9tX3VzZXIiOiAiQiIsDQogICAgInRhcmdldF91c2VyIjogIkEiDQp9
将上面加密后的2段字符串用点号连接在一起,如下所示:
ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ew0KICAgICJpc3MiOiAiWWFuZyBKV1QiLA0KICAgICJpYXQiOiAxNDQxNTkzNTAyLA0KICAgICJleHAiOiAxNDQxNTk0NzIyLA0KICAgICJhdWQiOiAid3d3LmV4YW1wbGUuY29tIiwNCiAgICAic3ViIjogInlhbmdAZXhhbXBsZS5jb20iLA0KICAgICJmcm9tX3VzZXIiOiAiQiIsDQogICAgInRhcmdldF91c2VyIjogIkEiDQp9
再对上面的字符串进行HS256算法加密,加密的时候需要我们提供一个密钥(比如我们设置密钥为63161014009),加密后的内容就是签名:
rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
最后再把签名通过点号拼在最后就得到了token:
ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ew0KICAgICJpc3MiOiAiWWFuZyBKV1QiLA0KICAgICJpYXQiOiAxNDQxNTkzNTAyLA0KICAgICJleHAiOiAxNDQxNTk0NzIyLA0KICAgICJhdWQiOiAid3d3LmV4YW1wbGUuY29tIiwNCiAgICAic3ViIjogInlhbmdAZXhhbXBsZS5jb20iLA0KICAgICJmcm9tX3VzZXIiOiAiQiIsDQogICAgInRhcmdldF91c2VyIjogIkEiDQp9.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
上面的三个加密都是可逆的,其中头部和主体信息任何人都能用base64解密,签名需要密钥才能解密。黑客没有密钥是不能伪造签名的,所以也不能伪造token。然后,在服务器端只需要重新对token里的头部和主体信息用密钥加密一次,然后和签名对比,就能知道这个token合不合法了。所以根本就不需要把token存在本地。
由于服务器不需要把token存在本地,节省了查找token的时间,在用户登出的时候,服务器也不需要销毁token等额外处理。所以jwt减少了服务器的很多压力。
值得一提的是,上面只是说明了一种jwt的模式,过程中都可以根据实际情况对流程进行改造。比如有的业务把token放到http header里面发送给服务器,有的业务把token放到url参数里面发送给服务器。
虽然jwt相比session-id有很多优势,但是它不能解决jwt失效的问题,除非设置过期时间。也就是说,如果把token放在服务器中储存的话,能够解决这个问题:就是假如我储存token在redis里面,每次认证的时候比较这个token,这样就能做到,用户A用A的信息登录之后,用户B再用A的信息登录,那么用户A的登录就会失效,因为储存了新的token(用户B收到的token)。但是jwt实现不了这种情形。
所以说,jwt只适用于有效期极短的token!!!它并不能取代session-id!!!
由于基于session-id的认证有如下缺点:
基于jwt的认证又有如下缺点:
所以对于一般的认证,现在通常用混合方法,具体如下:
这种认证的优点是:
授权码模式是Oauth2.0中最精彩的授权模式。它的步骤如下:
比如说,用户需要在豆瓣上注册登录,希望用用户的qq的信息来注册,这个时候就需要取得第三方QQ的授权,并拿取QQ里面这个用户的信息。
有下面几点需要注意:
黑客即使获取了第二步中的授权码也没用,因为黑客没有服务器id和密码,所以黑客还是不能访问QQ的服务器中的用户信息。
服务器id和密码是什么?服务器id和密码是豆瓣的“重定向URI”向QQ的认证服务器注册的时候获得的id和密码,作为豆瓣的标识。在注册的时候,QQ的认证服务器也会储存这个“重定向URI”,所以不同的用户都会导向同一个“重定向URI”。
第4步中的请求必须用https请求,否则授权code,服务器id和密码有可能被黑客截获,认证服务器发送回的令牌也可能被截获。
为什么需要一个“重定向URI”?首先,豆瓣的服务器id和密码不能储存在其它页面,它只能储存在豆瓣的“重定向URI”里面,否则很可能被泄漏。其次,“重定向URI”和认证服务器的通信必须为https,一般的豆瓣页面与认证服务器的通信可能不是https。
在第6步中,“重定向URI”可能会把令牌(token)发回给豆瓣原页面,也可能制造一个豆瓣的token发回给原页面。
Oauth2.0还有一个refresh_token。一般QQ的认证服务器发回的token的有效期很短,而refresh_token的有效期比较长,所以当token过期的时候,可以通过refresh_token向QQ的认证服务器申请token。
用户一共要进行3次uri跳转,一次是跳转到QQ的认证服务器。第二次是跳转到“重定向URI”。第三次跳转回以前的页面。其中第一次需要用户操作,点击是否同意QQ授权;第二次不需要用户操作,自动进行第三次跳转。
简单模式是不利用“重定向URI”,直接向认证服务器中申请token的模式。还是以豆瓣和QQ为例,它的步骤如下:
和授权码模式的授权的区别是,没有授权码,从而没有检测服务器id和密码。
黑客可以通过这2种方式进行攻击:1.黑客直接截取这个token。2.黑客伪造一个第三方网站,然后引导用户在伪造的第三方网站进行授权,最后就能理所当然的得到token了。授权码模式的授权可以防止第二种攻击,但是同样不能防止第一种攻击(可以利用https加强安全性)。
授权码模式的授权和简单模式的授权为了防止CSRF攻击,都会在跳转的URI上面加一个state参数来进行校验。
微信的静默授权和这个差不多,只是没有第二步,直接默认同意授权。
URL跳转才会在safari浏览器下面留下白条,非URL的URI跳转不会。由于微信的非静默授权会跳转到一个用户确认是否进行授权的URL,所以非静默授权会留下白条,静默授权不会。(不是因为有code才留下白条的)
为什么要在hash部分附带令牌?因为浏览器处理hash参数的时候不会使页面重新加载。(虽然说新的history api能够解决这个问题。)
如果认证服务器不支持跨域,那么只能用简单模式的授权。因为授权码模式的授权会提交服务器id,密码和code到认证服务器,所以需要认证服务器支持跨域的post请求;但是简单模式的授权全部是URI跳转,所以不用担心跨域。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
概述
因为做的项目涉及到用户认证和授权,所以好好总结了一下这块。
认证和授权
一般我们说的认证主要指的是用户登录认证;一般我们说的授权主要是第三方授权。
用户登录认证主要有2种方法,一种是基于session-id的认证,另一种是基于token的认证。
第三方授权主要是Oauth2.0标准的授权,它主要包括授权码模式的授权和简单模式的授权。
基于session-id的认证
基于session-id的认证是比较传统的认证方式,它包含以下几个步骤:
对于这种方式,我们前端的处理方式是:
需要注意的是,上面所有的一切都由服务器来完成,前端只请求接口就行了。服务器能够自己把会话id写入到浏览器的cookie里面。但是对于restful api,服务器是无状态的,所以在第2步需要前端手动把会话id储存在cookie里面,在第4步需要前端手动把会话id从cookie里面删除。
基于token的认证
基于token的认证主要是指json web token认证,即jwt认证。
它主要包含如下几个步骤:
需要注意的是,jwt认证有一个很重要的特点:服务器端没有储存token。
为什么服务器端不需要储存token呢,我们来看一下token的生成过程。
jwt这个字符串是由三部分组成:header(头部),payload(主体信息),signature(签名)。
头部是给JWT的基本信息,然后通过加密(base64加密)得到的。通过解密可以得到原始信息。比如下面这段基本信息:类型是jwt,签名算法是HS256。
加密后的头部如下:
主体信息是描述用户的信息,然后通过加密(base64加密)得到的。通过解密可以得到原始信息。比如下面这段主体信息。
加密后的主体信息如下:
将上面加密后的2段字符串用点号连接在一起,如下所示:
再对上面的字符串进行HS256算法加密,加密的时候需要我们提供一个密钥(比如我们设置密钥为63161014009),加密后的内容就是签名:
最后再把签名通过点号拼在最后就得到了token:
上面的三个加密都是可逆的,其中头部和主体信息任何人都能用base64解密,签名需要密钥才能解密。黑客没有密钥是不能伪造签名的,所以也不能伪造token。然后,在服务器端只需要重新对token里的头部和主体信息用密钥加密一次,然后和签名对比,就能知道这个token合不合法了。所以根本就不需要把token存在本地。
由于服务器不需要把token存在本地,节省了查找token的时间,在用户登出的时候,服务器也不需要销毁token等额外处理。所以jwt减少了服务器的很多压力。
值得一提的是,上面只是说明了一种jwt的模式,过程中都可以根据实际情况对流程进行改造。比如有的业务把token放到http header里面发送给服务器,有的业务把token放到url参数里面发送给服务器。
虽然jwt相比session-id有很多优势,但是它不能解决jwt失效的问题,除非设置过期时间。也就是说,如果把token放在服务器中储存的话,能够解决这个问题:就是假如我储存token在redis里面,每次认证的时候比较这个token,这样就能做到,用户A用A的信息登录之后,用户B再用A的信息登录,那么用户A的登录就会失效,因为储存了新的token(用户B收到的token)。但是jwt实现不了这种情形。
所以说,jwt只适用于有效期极短的token!!!它并不能取代session-id!!!
混合认证
由于基于session-id的认证有如下缺点:
基于jwt的认证又有如下缺点:
所以对于一般的认证,现在通常用混合方法,具体如下:
这种认证的优点是:
授权码模式的授权
授权码模式是Oauth2.0中最精彩的授权模式。它的步骤如下:
比如说,用户需要在豆瓣上注册登录,希望用用户的qq的信息来注册,这个时候就需要取得第三方QQ的授权,并拿取QQ里面这个用户的信息。
有下面几点需要注意:
黑客即使获取了第二步中的授权码也没用,因为黑客没有服务器id和密码,所以黑客还是不能访问QQ的服务器中的用户信息。
服务器id和密码是什么?服务器id和密码是豆瓣的“重定向URI”向QQ的认证服务器注册的时候获得的id和密码,作为豆瓣的标识。在注册的时候,QQ的认证服务器也会储存这个“重定向URI”,所以不同的用户都会导向同一个“重定向URI”。
第4步中的请求必须用https请求,否则授权code,服务器id和密码有可能被黑客截获,认证服务器发送回的令牌也可能被截获。
为什么需要一个“重定向URI”?首先,豆瓣的服务器id和密码不能储存在其它页面,它只能储存在豆瓣的“重定向URI”里面,否则很可能被泄漏。其次,“重定向URI”和认证服务器的通信必须为https,一般的豆瓣页面与认证服务器的通信可能不是https。
在第6步中,“重定向URI”可能会把令牌(token)发回给豆瓣原页面,也可能制造一个豆瓣的token发回给原页面。
Oauth2.0还有一个refresh_token。一般QQ的认证服务器发回的token的有效期很短,而refresh_token的有效期比较长,所以当token过期的时候,可以通过refresh_token向QQ的认证服务器申请token。
用户一共要进行3次uri跳转,一次是跳转到QQ的认证服务器。第二次是跳转到“重定向URI”。第三次跳转回以前的页面。其中第一次需要用户操作,点击是否同意QQ授权;第二次不需要用户操作,自动进行第三次跳转。
简单模式的授权
简单模式是不利用“重定向URI”,直接向认证服务器中申请token的模式。还是以豆瓣和QQ为例,它的步骤如下:
有下面几点需要注意:
和授权码模式的授权的区别是,没有授权码,从而没有检测服务器id和密码。
黑客可以通过这2种方式进行攻击:1.黑客直接截取这个token。2.黑客伪造一个第三方网站,然后引导用户在伪造的第三方网站进行授权,最后就能理所当然的得到token了。授权码模式的授权可以防止第二种攻击,但是同样不能防止第一种攻击(可以利用https加强安全性)。
授权码模式的授权和简单模式的授权为了防止CSRF攻击,都会在跳转的URI上面加一个state参数来进行校验。
微信的静默授权和这个差不多,只是没有第二步,直接默认同意授权。
URL跳转才会在safari浏览器下面留下白条,非URL的URI跳转不会。由于微信的非静默授权会跳转到一个用户确认是否进行授权的URL,所以非静默授权会留下白条,静默授权不会。(不是因为有code才留下白条的)
为什么要在hash部分附带令牌?因为浏览器处理hash参数的时候不会使页面重新加载。(虽然说新的history api能够解决这个问题。)
如果认证服务器不支持跨域,那么只能用简单模式的授权。因为授权码模式的授权会提交服务器id,密码和code到认证服务器,所以需要认证服务器支持跨域的post请求;但是简单模式的授权全部是URI跳转,所以不用担心跨域。
The text was updated successfully, but these errors were encountered: