一 常用的认证机制
HTTP Basic Auth
HTTP Base Auth 在HTTP中,基本认证是一种用来允许Web浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登陆验证方式,通常用户名和密码会通过HTTP头传递。
在发送之前是以用户名加一个冒号串接上口令,并将得出的结果字符串在用Base64算法编码。例如提供的用户名是Admin,口令是open abcd,则拼接后的结果就是Admin: openabcd,然后在将其用base64编码的字符串发送出去,由接收者解码得到一个由冒号分割的用户名和口令的字符串。
优点:
基本认证的一个优点就是基本上所有流行的网页浏览器都支持基本认证
缺点:
由于用户名和密码都是base64编码的,base64 编码是可逆的,所以用户名和密码可以认为是明文。所以只有在客户端和服务器主机之间的连接是安全可信的前提下才可以使用
OAuth
OAuth是一个关于授权的开放网络标准。允许用户提供一个令牌,而不是用户名和密码来访问他们存放的特定服务提供着的数据。现在的版本是2.0版。
严格来说。OAuth2不是一个标准的协议,而是一个安全的授权框架。它详细描述了系统中的各个角色,用户,服务前端应用(比如APi)以及客户端(比如网站和移动app)之间怎么实现相互认证。
优点:
快速开发
实施代码量小
维护工 作减少
如果设计的API要被不同的App使用,并且每个app使用的方式也不一样,使用OAuth2是个不错的选择。
缺点:
OAuth2是一个安全框架,描述了在各种不同场景下,多个应用之间的授权问题。有海量的资料需要学习,要完全理解需要花费大量的时间。
OAth2不是一个严格的标准协议,因此在实施过程中更容易出错
jwt认证
Json web token(jwt),根据官网的定义,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准,该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录场(SSO)场景。JWT的声明一般用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便从资源服务器获取资源,也可以增加一些额外的其他逻辑所必须的声明信息,该token也可以直接被用户认证,也可被加密。
jwt 特点
- 体积小,因而传输速度快
- 传输方式多样,可以通过URL/POST参数 HTTP头部等方式传输
- 严格的结构化,它自身(payload)就包含了所有与用户相关的验证信息,如用户可访问路由,访问有效期等信息,服务器无需再去连接数据库验证信息的有效性,并且payload支持为你的应用而定制化。
- 支持跨域验证,可以应用于单点登录。
j w t原理
JWT是Auth0提出的通过对json进行加密签名来实现授权验证的方案,编码之后的JWT看起来是这样的一窜字符
IUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQddddd
由点分为三段,通过解码可以得到:
1 头部(Header)
// 包括类别(typ)、加密算法(alg);
{
"alg": "HS256",
"typ": "JWT"
}
j w t的头部包含两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法通常直接使用HMAC SHA256
然后将头部进行base64加密(该加密是对称加密的),构成了第一部分。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2 负荷(p a ylaod)
载荷就是存放有效信息的地方。这些有效信息包含三个部分
- 标准中注册声明
- 公共的声明
- 私有的声明
公共的声明:
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密。
私有的声明:
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
下面是一个例子:
// 包括需要传递的用户信息;
{
"iss": "Online JWT Builder",
"iat": 1416797419,
"exp": 1448333419,
"aud": "www.gusibi.com",
"sub": "uid",
"nickname": "goodspeed",
"username": "goodspeed",
"scopes": [ "admin", "user" ]
}
- iss: 该JWT的签发者,是否使用是可选的;
- sub: 该JWT所面向的用户,是否使用是可选的
- aud: 接收该JWT的一方,是否使用是可选的;
- exp(expires): 什么时候过期,这里是一个Unix时间戳,是否使用是可选的;
- iat(issued at): 在什么时候签发的(UNIX时间),是否使用是可选的;
其他还有: - nbf (Not Before):如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟;,是否使用是可选的;
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
将上面的JSON对象进行base64编码可以得到下面的字符串。这个字符串我们将它称作JWT的Payload(载荷
eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0
信息会暴露:由于这里用的是可逆的base64 编码,所以第二部分的数据实际上是明文的。我们应该避免在这里存放不能公开的隐私信息。
3 签名(signature)
// 根据alg算法与私有秘钥进行加密得到的签名字串;
// 这一段是最重要的敏感信息,只能在服务端解密;
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECREATE_KEY
)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret
将上面的两个编码后的字符串都用句号.连接在一起(头部在前),就形成了:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9
最后,我们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,我们还需要提供一个密钥(secret)。如果我们用 secret 作为密钥的话,那么就可以得到我们加密后的内容:
pq5IDv-yaktw6XEa5GEv07SzS9ehe6AcVSdTj0Ini4o
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0.pq5IDv-yaktw6XEa5GEv07SzS9ehe6AcVSdTj0Ini4o
签名的目的:签名实际上是对头部以及载荷内容进行签名。所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。这样就能保证token不会被篡改。
token 生成好之后,接下来就可以用token来和服务器进行通讯了。
JWT 使用场景
JWT的主要优势在于使用无状态、可扩展的方式处理应用中的用户会话。服务端可以通过内嵌的声明信息,很容易地获取用户的会话信息,而不需要去访问用户或会话的数据库。在一个分布式的面向服务的框架中,这一点非常有用。
但是,如果系统中需要使用黑名单实现长期有效的token刷新机制,这种无状态的优势就不明显了
优点:
快速开发
不需要cookie
JSON在移动端的广泛应用
不依赖于社交登录
相对简单的概念理解
缺点:
Token有长度限制
Token不能撤销
需要token有失效时间限制(exp)