OAuth2
1,OAuth2 介绍
OAuth 是一个开放标准,该标准允许用户让第三方应用访问该用户在某一网站上存储的私密资源 (如头像、照片、视频等),并且在这个过程中无须将用户名和密码提供给第三方应用。通过令牌 (token) 可以实现这一功能。每一个令牌授权一个特定的网站在特定的时间段内允许可访问特定的资源。OAuth 让用户可以授权第三方网站灵活访问它们存储在另外一些资源服务器上的特定信息,而非所有的内容。对于用户而言,我们在互联网应用中最常见的 OAuth 应用就是各种第三方登录,例如 QQ授权登录、微信授权登录、微博授权登录、GitHub 授权登录等。
2,OAuth2 授权流程
- 用户打开客户端以后,客户端要求用户给予授权。
- 用户同意给予客户端授权。
- 客户端使用上一步获得的授权,向认证服务器申请令牌。
- 认证服务器对用户端进行认证以后,确认无误,同意发放令牌。
- 客户端使用令牌,向资源服务器申请资源。
- 资源服务器确认令牌无误,同意向客户端开放资源。
四个角色:
以上面的 QQ 登录百度为例
- Client :第三方应用,就是上述的百度。
- Resource Owner:资源所有者,就是指用户自己。
- Authorizetion Server :授权服务器,就是上述的 QQ。
- Resource Server :资源服务器,也是上述的 QQ。
3,四种授权模式
1. 授权码模式
常见的第三方平台登录功能基本都是使用这种模式。(安全性高)
1. 一般需要在认证服务器登记。如 gitee:
2. 前端去获取 code
比如 gitee,客户端前端页面调用 https://gitee.com/oauth/authorize 来获取授权码。
<a href="https://gitee.com/oauth/authorize?client_id=fc991207432bb989bde8d8a82e2bfddc65b9bd2cc9cf86b1bd7cc097e1ecb505&redirect_uri=http://localhost:18081/gitee/authorize/token&response_type=code" target="_blank" title="gitee登录">gitee登录</a>
3. 后端获取 token
前端获取 code 的 的接口 https://gitee.com/oauth/authorize 有个回调接口,其中一个参数是 redirect_url,这个路径就是我们后端接收 code,然后调用 https://gitee.com/oauth/token 来获取 accessToken 的接口。
/**
* 授权码模式:
* 1,前端嗲用
* 前端调用 gitee https://gitee.com/oauth/authorize,通过参数设置这个回调接口,获取 code
* 2,调用 https://gitee.com/oauth/token 获取 token,返回前端
* */
@RequestMapping("/authorize/token")
public Result<String> giteeToken(String code){
//获取 token
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-type", "application/x-www-form-urlencoded");
MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("code", code);
param.add("client_id", clientId);
param.add("client_secret", clientSecret);
param.add("grant_type", "authorization_code");
//这个回调不知道有啥用,但是必须有
param.add("redirect_uri", "http://localhost:18081/gitee/authorize/token");
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(param, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(tokenUrl, entity, String.class);
return Result.success( responseEntity.getBody() );
}
2. 简化模式
简化模式是不需要第三方服务端(客户端)参与,直接在浏览器中向授权服务器申请令牌(token),如果网站是纯静态页面,则可以采用这种方式。
3. 密码模式
密码模式是用户把用户名/密码直接告诉客户端,客户端使用在这些信息项授权服务器申请令牌(token)。这需要用户对客户端高度信任,例如客户端应用和服务器提供商就是同一家公司。
1. 一般需要在认证服务器登记。如 gitee:
2. 直接调用接口传用户名和密码
/**
* 密码模式
* */
@RequestMapping("/pwd/token")
public Result<String> giteeToken(String username, String password){
//获取 token
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-type", "application/x-www-form-urlencoded");
MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("username", username);
param.add("password", password);
param.add("client_id", clientId);
param.add("client_secret", clientSecret);
param.add("grant_type", "password");
//user_info projects pull_requests issues notes keys hook groups gists enterprises
param.add("scope", "projects user_info issues notes");
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(param, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(tokenUrl, entity, String.class);
return Result.success( responseEntity.getBody() );
}
4. 客户端模式
客户端模式是指客户端使用自己的名义而不是用户的名义向授权服务器提供申请授权。严格来说,客户端模式并不能算作 OAuth 协议解决问题的一种解决方案,但是对于开发者而言,在一些为移动端提供的授权服务器上使用这种模式还是非常方便的。