OAUTH2 客户端模拟授权
项目背景
目前公司项目需要和其他平台对接restful接口,但接口使用Spring Security OAuth 2.0做了授权认证,需要通过http模拟请求方式获取Token信息。没有办法只能霸王硬上身了,呵呵。废话不多说,直接看重点吧,下面是我的总结。
OAUTH2介绍
百度说:OAUTH2协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH2的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH2是安全的。
俺说:百度说OAUTH2是一个安全标准,那我到Google找了下oauth2标准,目前找到的标准是rfc6749标准协议,https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.4。
目前OAUTH2授权模式:
1.授权码模式
2.简化模式
3.密码模式
4.客户端模式
OAUTH2授权方式
1.授权码模式(authorization code)
目前QQ、微博、Google 、 github 第三方应用登录都是使用授权码模式。流程如下:
授权码.png第一步,发送GET请求,传递参数
参数名称 | 参数值 | 描述 |
---|---|---|
response_type | code | 授权码模式 |
client_id | 由授权服务提供,类似微信中app_id | 客户端编号 |
redirect_uri | 回调地址 | 重定向地址,授权会将code编码回转 |
scope | 由授权服务提供 | 作用域,用于权限控制,可选性 |
state | 由授权服务提供表示客户端的当前状态,可以指定任意值,授权服务器会原封不动地返回这个值 |
请求实例:
http://localhost:8080/oauth/authorize?client_id=app&response_type=code&redirect_uri=http://www.baidu.com
第二步,授权页面填写:用户名、密码、等信息,或者二维码扫码。授权页面通过认证以后会重定向到回调地址,回调地址中包含code(授权码)。
第三步,发送POST请求,使用授权码对换token信息。
请求实例:
http://localhost:8080/oauth/token?client_id=app&grant_type=authorization_code&redirect_uri=http://www.baidu.com&client_secret=app&code=xls123
2.简化模式(implicit)
implicit模式和授权码模式(authorization_code)访问差不多,相比之下,少了一步获取code的步骤,而是直接获取token。如果对第三方平台信任很高,可以使用,流程下图:
简易模式.png
第一步,GET请求传递参数
参数名称 | 参数值 | 描述 |
---|---|---|
response_type | token | 简化模式 |
client_id | 由授权服务提供,类似微信中app_id | 客户端编号 |
redirect_uri | 回调函数 | 重定向地址,授权会将token信息返回 |
请求实例:
http://localhost:8080/oauth/authorize?response_type=token&client_id=app&redirect_uri=http://www.baidu.com
3.密码模式(password)
客户端提供自己的用户名和密码通过url参数传递,向"服务提供商"索要授权。
流程图如下:
密码模式.png第一步,POST请求传递参数
参数名称 | 参数值 | 描述 |
---|---|---|
grant_type | password | 表示授权类型,此处的值固定为"password",必选项 |
username | 由授权服务提供 | 用户名,必选项。 |
password | 由授权服务提供 | 密码,必选项。 |
scope | 由授权服务提供 | 权限范围,可选项 |
请求实例:
http://localhost:8080/oauth/token?username=app&password=app&scope=app&grant_type=password&client_id=app&redirect_uri=http://www.baidu.com
4.客户端模式(client_credentials)
客户端提供用户名和密码,按basic认证方式传递,并且向"服务提供商"索要授权。
流程图如下:
客户端模式.png
请求实例:
http://localhost:8080/oauth/token?grant_type=client_credentials
第一步,POST请求参数
参数名称 | 参数值 | 描述 |
---|---|---|
grant_type | password | 表示授权类型,此处的值固定为"password",必选项 |
用户名和密码使用basic认证方式,在header中加入协议头,参考如下:
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l //YWxhZGRpbjpvcGVuc2VzYW1l 生成规则:base64(用户名:密码)
http模拟请求oauth2
1.引入Maven依赖
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.14</version>
</dependency>
</dependencies>
2.JAVA代码实例
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import java.net.HttpCookie;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
public class OAuth2Utils {
public static void main(String[] args) {
// 授权码认证
authCode();
//简化认证
implicit();
//密码认证
password();
//客户端模式
client_credentials();
}
//客户端模式
private static void client_credentials() {
System.out.println("---------------客户端认证------------------");
//1.直接调用获取token的接口,将用户名和密码传递过去
HttpResponse response=HttpUtil.createPost("http://localhost:8080/oauth/token?grant_type=client_credentials")
.basicAuth("app","app") //客户端认证,使用basic认证方式专递账号和密码
.execute();
System.out.println(response.body());
}
/**
* 密码认证
*/
private static void password() {
System.out.println("---------------密码认证------------------");
//1.直接调用获取token的接口,将用户名和密码传递过去
HttpResponse response=HttpUtil.createPost("http://localhost:8080/oauth/token?username=app&password=app&scope=app&grant_type=password&client_id=app&redirect_uri=http://www.baidu.com")
.basicAuth("app","app")//这里是oauth2认证,我做basic认证,如果没有可以去掉
.execute();
System.out.println(response.body());
}
/**
* 简化认证
*/
private static void implicit() {
System.out.println("---------------简化认证------------------");
//1.调用简化模式接口,直接获取token
HttpResponse response = HttpUtil.createGet(" http://localhost:8080/oauth/authorize?response_type=token&client_id=app&redirect_uri=http://www.baidu.com")
.basicAuth("app", "app")//这里是oauth2认证,我做basic认证,如果没有可以去掉
.execute();
//2.获取重定向数据
String location = response.header("Location");
location = location.replaceAll("#", "?");
Map<String, List<String>> stringListMap = HttpUtil.decodeParams(location, Charset.defaultCharset());
System.out.println(stringListMap);
}
/**
* 授权码认证
*/
private static void authCode() {
System.out.println("---------------授权码认证------------------");
//1.跳转到授权页面
HttpResponse response = HttpUtil.createGet("http://localhost:8080/oauth/authorize?client_id=app&response_type=code&redirect_uri=http://www.baidu.com")
.basicAuth("app", "app") //这里是oauth2认证,我做basic认证,如果没有可以去掉
.execute();
//2.获取302重定向信息
String location = response.header("Location");
//3.获取第一次sessionId会话,保证一次会话
HttpCookie jsessionid = response.getCookie("JSESSIONID");
//4.判断第一次跳转授权页面是否重定向,如果未重定向则模拟授权按钮
if(location==null){
//5.填写授权页面的信息,获取授权权限
response= HttpUtil.createPost("http://localhost:8080/oauth/authorize?client_id=app&response_type=code&redirect_uri=http://www.baidu.com")
.basicAuth("app", "app") //这里是oauth2认证,我做basic认证,如果没有可以去掉
.form("user_oauth_approval","true")
.form("scope.app","true")
.form("authorize","授权")
.cookie(jsessionid)
.execute();
//获取http session会话
jsessionid = response.getCookie("JSESSIONID");
}
//5.获取302重定向url地址信息,里面包好授权码
location = response.header("Location");
//解析url信息
Map<String, List<String>> stringListMap = HttpUtil.decodeParams(location, Charset.defaultCharset());
jsessionid = response.getCookie("JSESSIONID");
//获取授权码
String code=stringListMap.get("code").get(0);
//6.通过授权码获取token信息
response = HttpUtil.createPost("http://localhost:8080/oauth/token?client_id=app&grant_type=authorization_code&redirect_uri=http://www.baidu.com&client_secret=app&code=" + code)
.basicAuth("app", "app") //这里是oauth2认证,我做basic认证,如果没有可以去掉
.cookie(jsessionid)
.execute();
JSONObject jsonObject = JSONUtil.parseObj(response.body());
System.out.println(jsonObject);
}
}
3.oauth2服务返回结构体
---------------授权码认证------------------
{"token_type":"bearer","access_token":"9768a799-68f3-4440-873e-f83a8e2ff9ea","refresh_token":"1dbfbaac-d2e2-4082-b77a-44eef88ff66c","scope":"app","expires_in":139702}
---------------简化认证------------------
{access_token=[9768a799-68f3-4440-873e-f83a8e2ff9ea], token_type=[bearer], expires_in=[139702], scope=[app]}
---------------密码认证------------------
{"access_token":"9768a799-68f3-4440-873e-f83a8e2ff9ea","token_type":"bearer","refresh_token":"1dbfbaac-d2e2-4082-b77a-44eef88ff66c","expires_in":139702,"scope":"app"}
---------------客户端认证------------------
{"access_token":"de676cbe-f6ab-4fa1-9450-80364230cf0c","token_type":"bearer","expires_in":139702,"scope":"app"}