HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码便可,但因为有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的愈来愈少。所以,在开发对外开放的RESTful API时,尽可能避免采用HTTP Basic Auth。javascript
OAuth(开放受权)是一个开放的受权标准,容许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。html
OAuth容许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每个令牌受权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户能够受权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非全部内容
下面是OAuth2.0的流程:java
这种基于OAuth的认证机制适用于我的消费者类的互联网产品,如社交类APP等应用,可是不太适合拥有自有认证权限管理的企业应用。git
Cookie认证机制就是为一次请求认证在服务端建立一个Session对象,同时在客户端的浏览器端建立了一个Cookie对象;经过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当咱们关闭浏览器的时候,cookie会被删除。但能够经过修改cookie 的expire time使cookie在必定时间内有效。github
使用基于 Token 的身份验证方法,大概的流程是这样的:web
Token机制相对于Cookie机制又有什么好处呢?算法
实施 Token 验证的方法挺多的,还有一些标准规范,其中JSON Web Token(JWT)是一个很是轻巧的规范 。JWT 标准的 Token 有三个部分:数据库
中间用点分隔开,而且都会使用 Base64 编码,因此真正的 Token 看起来像这样:json
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
每一个 JWT token 里面都有一个 header,也就是头部数据。里面包含了使用的算法,这个 JWT 是否是带签名的或者加密的。主要就是说明一下怎么处理这个 JWT token 。后端
头部里包含的东西可能会根据 JWT 的类型有所变化,好比一个加密的 JWT 里面要包含使用的加密的算法。惟一在头部里面要包含的是 alg 这个属性,若是是加密的 JWT,这个属性的值就是使用的签名或者解密用的算法。若是是未加密的 JWT,这个属性的值要设置成 none。
示例:
{ "alg": "HS256" }
意思是这个 JWT 用的算法是 HS256。上面的内容得用 base64url 的形式编码一下,因此就变成这样:
eyJhbGciOiJIUzI1NiJ9
Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也能够添加其它须要的内容。下面是标准字段:
好比下面这个 Payload ,用到了 iss 发行人,还有 exp 过时时间这两个标准字段。另外还有两个自定义的字段,一个是 name ,还有一个是 admin 。
{ "iss": "ninghao.net", "exp": "1438955445", "name": "wanghao", "admin": true }
使用 base64url 编码之后就变成了这个样子:
eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ
JWT 的最后一部分是 Signature ,这部份内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个至关因而一个密码,这个密码秘密地存储在服务端。
const encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); HMACSHA256(encodedString, 'secret');
处理完成之后看起来像这样:
SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
最后这个在服务端生成而且要发送给客户端的 Token 看起来像这样:
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
客户端收到这个 Token 之后把它存储下来,下回向服务端发送请求的时候就带着这个 Token 。服务端收到这个 Token ,而后进行验证,经过之后就会返回给客户端想要的资源。
Java中对JWT的支持能够考虑使用JJWT开源库;JJWT实现了JWT, JWS, JWE 和 JWA RFC规范;下面将简单举例说明其使用:
maven导入
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
建立和解析token
/** * 解析JWT * @param jsonWebToken * @param base64Security * @return */ public static Claims parseJWT(String jsonWebToken, String base64Security) { try { Claims claims = Jwts.parser() .setSigningKey(DatatypeConverter.parseBase64Binary(base64Security)) .parseClaimsJws(jsonWebToken).getBody(); return claims; } catch (Exception ex) { return null; } } /** * 建立JWT * @param no * @param userId * @param issuer * @param TTLMillis * @param base64Security * @return */ public static String createJWT(String no, String userId, String issuer, long TTLMillis, String base64Security) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); //生成签名密钥 byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); //添加构成JWT的参数 JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") .claim("no", no) .setSubject(userId) .setIssuer(issuer) .signWith(signatureAlgorithm, signingKey); //添加Token过时时间 if (TTLMillis >= 0) { long expMillis = nowMillis + TTLMillis; Date exp = new Date(expMillis); builder.setExpiration(exp).setNotBefore(now); } //生成JWT return builder.compact(); }
参考: