HTTP Basic Auth
在HTTP中,基本认证(Basic access authentication)是一种用来允许网页浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。
在发送之前是以用户名追加一个冒号然后串接上口令,并将得出的结果字符串再用Base64算法编码。例如,提供的用户名是Aladdin、口令是open sesame,则拼接后的结果就是Aladdin:open sesame,然后再将其用Base64编码,得到QWxhZGRpbjpvcGVuIHNlc2FtZQ==。最终将Base64编码的字符串发送出去,由接收者解码得到一个由冒号分隔的用户名和口令的字符串。
有时在登录网站时会由浏览器弹出一个框, 这个就是http的基本认证. 不过现在已经很少用了
OAuth
OAuth 是一个关于授权(authorization)的开放网络标准。允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。现在的版本是2.0版。
严格来说,OAuth2不是一个标准协议,而是一个安全的授权框架。它详细描述了系统中不同角色、用户、服务前端应用(比如API),以及客户端(比如网站或移动App)之间怎么实现相互认证。
名词定义
-
Third-party application: 第三方应用程序,又称"客户端"(client)
-
HTTP service:HTTP服务提供商
-
Resource Owner:资源所有者,通常称"用户"(user)。
-
User Agent:用户代理,比如浏览器。
-
Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。
-
Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。
像QQ登录这种第三方登录一般都是使用的OAuth认证, 认证服务器是第三方服务器, 一般都是用户有个唯一的token, 客户或浏览器登录成功后会得到1个code, 然后带着这个code去访问你的网站, 你在带着这个code去访问第三方的认证服务器, 就可以获得用户的唯一token, 如果要获得这个用户的更多信息的话还可以带着token再发一次请求, 就能得到用户的一些信息了
JWT
Json web token (JWT)
, 根据官网的定义,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
jwt特点
-
体积小,因而传输速度快
-
传输方式多样,可以通过URL/POST参数/HTTP头部等方式传输
-
严格的结构化。它自身(在 payload 中)就包含了所有与用户相关的验证消息,如用户可访问路由、访问有效期等信息,服务器无需再去连接数据库验证信息的有效性,并且 payload 支持为你的应用而定制化。
-
支持跨域验证,可以应用于单点登录。
JWT组成
JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:
- Header
- Payload
- Signature
一个加密后的字符串如下所示, 由.分为3段
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
1. 头部
jwt的头部包含两部分信息:
-
声明类型,这里是jwt
-
声明加密的算法 通常直接使用 HMAC SHA256
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分。
import base64,json # 头部 headr = { "alg": "HS256", "typ": "JWT" } crypt = base64.standard_b64encode(json.dumps(headr).encode("utf8")) print(crypt) # eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9
2. 荷载
载荷就是存放有效信息的地方。这些有效信息包含三个部分:
-
标准中注册声明
-
公共的声名: 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密。
-
私有的声明: 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
标准注册声明中的字段
- iss:发行人
- exp:到期时间
- sub:主题
- aud:用户
- nbf:在此之前不可用
- iat:发布时间
- jti:JWT ID用于标识该JWT
将荷载的JSON对象进行base64编码
可以得到第二部分的加密字符串。
payload = { "iss": "Online JWT Builder", "iat": 1416797419, "exp": 1448333419, "aud": "www.gusibi.com", "sub": "uid", "nickname": "佩奇", "username": "peiqi", } crypt = base64.standard_b64encode(json.dumps(payload).encode("utf8")) print(crypt)
得到结果
eyJpc3MiOiAiT25saW5lIEpXVCBCdWlsZGVyIiwgImlhdCI6IDE0MTY3OTc0MTksICJleHAiOiAxNDQ4MzMzNDE5LCAiYXVkIjogInd3dy5ndXNpYmkuY29tIiwgInN1YiI6ICJ1aWQiLCAibmlja25hbWUiOiAiXHU0ZjY5XHU1OTQ3IiwgInVzZXJuYW1lIjogInBlaXFpIn0
3. 签名
签名由编码过的header, 编码过的payload, 再有header中的加密算法加上秘钥生成
咱们上面指定的是HS256
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), SECREATE_KEY )
签名的目的
:签名实际上是对头部以及载荷内容进行签名。所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。
这样就能保证token不会被篡改。
python中的pyjwt模块可以完成以上工作, 这个是官网https://pyjwt.readthedocs.io/en/latest/, 用起来也是比较简单的, 只需要构造Payload就可以了. header里的加密算法是后指定的
import jwt encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') print(encoded_jwt) 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg' print(jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])) {'some': 'payload'}