刷新令牌
为何需要刷新令牌?
在生成访问令牌的时附加过期时间expires_in
访问令牌会在一定的时间后失效。访问令牌失效,资源拥有者给第三方软件的授权失效,第三方软件无法继续访问资源拥有者的受保护资源。
如果还想继续使用三方软件,必须重新点击授权按钮,比如我给xx授权后,正在愉快地编写我公众号的文章呢,刚准备使用 xx 的导入文章功能,突然xx再次让我进行授权。此刻,我可很崩溃!
于是,OAuth 2.0中引入刷新令牌,即刷新访问令牌access_token的值。有了刷新令牌,用户在一定期限内无需重新授权,就可继续使用三方软件。
刷新令牌的原理
刷新令牌也是给第三方软件使用的,同样需要遵循先颁发再使用的原则。
颁发刷新令牌
颁发刷新令牌和颁发访问令牌一起实现,都在过程二的步骤三生成访问令牌access_token中生成的。即第三方软件得到一个访问令牌的同时,也会得到一个刷新令牌:
Map<String,String> refreshTokenMap = new HashMap<String, String>(); String refreshToken = generateRefreshToken(appId,"USERTEST");//生成刷新令牌refresh_token的值 private String generateRefreshToken(String appId,String user){ String refreshToken = UUID.randomUUID().toString(); refreshTokenMap.put(refreshToken,appId+"|"+user+"|"+System.currentTimeMillis()); return refreshToken; }
为什么要一起生成访问令牌和刷新令牌
刷新令牌初衷是在访问令牌失效时,为了不让用户频繁手动授权,通过系统重新请求生成一个新的访问令牌。若访问令牌失效,而“身边”又没有一个刷新令牌可用,岂不是又要麻烦用户手动授权。所以,它必须和访问令牌一起生成。
使用刷新令牌
OAuth 2.0规范中,刷新令牌是一种特殊的授权许可类型,是嵌入在授权码许可类型下的一种特殊许可类型。在授权服务的代码里,接收到这种授权许可请求时,会先比较grant_type和 refresh_token的值。
这其中的流程主要包括如下两大步骤。
第一步-接收刷新令牌请求,验证基本信息
请求中的grant_type值为refresh_token。
String grantType = request.getParameter("grant_type"); if("refresh_token".equals(grantType)){ }
和颁发访问令牌前的验证流程一样,也要验证第三方软件是否存在。这里需同时验证刷新令牌是否存在,目的就是要保证传过来的刷新令牌的合法性。
String refresh_token = request.getParameter("refresh_token"); if(!refreshTokenMap.containsKey(refresh_token)){ //该refresh_token值不存在 }
另外,我们还需要验证刷新令牌是否属于该第三方软件。授权服务是将颁发的刷新令牌与第三方软件、当时的授权用户绑定在一起的,因此这里需要判断该刷新令牌的归属合法性。
String appStr = refreshTokenMap.get("refresh_token"); if(!appStr.startsWith(appId+"|"+"USERTEST")){ //该refresh_token值不是颁发给该第三方软件的 }
一个刷新令牌被使用后,授权服务需要将其废弃,并重新颁发一个刷新令牌。
第二步,重新生成访问令牌
生成访问令牌的处理流程,与颁发访问令牌环节的生成流程一致。授权服务会将新的访问令牌和新的刷新令牌,一起返回给第三方软件。
总结
授权服务的核心:先颁发授权码code值,再颁发访问令牌access_token值。
在颁发访问令牌同时还会颁发刷新令牌refresh_token值,这种机制可以在无须用户参与的情况下用于生成新的访问令牌。正如我们讲到的小明使用小兔软件的例子,当访问令牌过期的时候,刷新令牌的存在可以大大提高小明使用小兔软件的体验。
授权还要有授权范围,不能让第三方软件获得比注册时权限范围还大的授权,也不能获得超出了用户授权的权限范围,始终确保最小权限安全原则。
若access_token未超时,那么进行refresh_token有两种方式
不会改变access_token,但超时时间会刷新,相当于续期access_token
更新access_token的值,我们建议【统一更新access_token的值】。
延期access_token并不是一个最好的方式,尽管有的开放平台是这么做的。