Chaptor1 OAuth 2.0 Foundati1ons
最近在通过《OAuth 2.0 Cookbook_Protect Your Web Applications using Spring Security-Packt Publishing(2017)》这本书学习Spring security,英文书看得很头疼,网上也没有对应的中文翻译,就当是半翻译半自学笔记,如果能帮到其他人,就更好了。
第一章的主要内容如下:
- 准备环境
- client端从facebook获取用户的联系人
- 在server端从facebook读取用户的联系人
- 通过oauth2.0 linkedin受保资源
- 通过oauth2.0 google受保资源,并传入用户session
在开始学习之前,先看这幅图
这幅图清楚地展现了OAuth2.0的四个主要部分:
- Resource owner: 授权给第三方应用使用资源。
- Resource server:保存,保护用户资源,通常和authorization server共同实现为一个服务,例如图中的OAuth2.0 Provider。
- Authorization server
- Client :第三方应用表现为Client
准备环境
本书的例子使用Java ,spring boot,maven。请预先搭好相应环境
Reading the user's contacts from facebook on the client side
客户端从Facebook读取用户的联系人
1. 首先注册一个facebook账号,并进入开发者页面 https://developers.facebook.com/apps/
2. 点击Create a New App ,Create App ID ,然后会跳转进入如下页面
3.选择创建一个“Facebook Login”的“Web”产品,输入网址地址,本文输入"http://clientimplicit.test"
4.继续,输入登录成功后的跳转URL,例如”http://localhost:8080/callback. “,保存修改
5.在左边面板选择“设置”->“基本”,可以获取appid, app secret,至此,facebook的设置暂时完成。
6.现在新建一个spring 项目,加入“web”和“Thymeleaf ”依赖,在templates文件夹下创建client.html 文件
7.将以下代码,写入client.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Facebook - client side integration</title></head>
<body>
Press the following button to start the implicit flow.
<button id="authorize" type="button">Authorize</button>
<div id="box"></div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function () {
$("#authorize").click(makeRequest);
});
//点击按钮,往授权中心发请求
function makeRequest() {
var auth_endpoint =
"https://www.facebook.com/v3.0/dialog/oauth",
response_type = "token",
client_id = "1741430609244678",
redirect_uri = "https://localhost:8089/callback",
scope = "public_profile user_friends";
var request_endpoint = auth_endpoint + "?" +
"response_type=" + response_type + "&" +
"client_id=" + client_id + "&" +
"redirect_uri=" + encodeURI(redirect_uri) + "&" +
"scope=" + encodeURI(scope);
window.location.href = request_endpoint;
}
/*]]>*/
</script>
</html>
8.此外,我们还要将一个URL映射到这个html文件,于是还要将以下代码加入Application.java文件
@Controller
@SpringBootApplication
public class ClientImplicitFacebookApplication {
public static void main(String[] args) {
SpringApplication.run(ClientImplicitFacebookApplication.class, args);
}
@GetMapping("/")
public String client() {
return "client";
}
}
9.启动项目,点击Authorize 按钮,在完成验证以后,可以在浏览器看到如下的重定向URL:
http://localhost:8080/callback#access_token=EAAbsiSHMZC60BANUwKBDCY
eySZCjcBpvFuUO1gXsfTGwWjnZAFTAZBIJB62jdUroAcNuZAVWO24yeqo0iazWYytVg
rQ1bgNWI8vm07Ws4ZCHXpGridHfZB6PQ1rzM4BzP29IljgTTuBLZBFQBEnEn2LJiOWJ
jA8J6Y73BLcjIe2vVMZB9c2GnZBpiK4iZAWEtkTsMEZD&expires_in=7152
10.现在,我们可以提取access_token和expires_in来获取用户的朋友信息了.首先,我们要写一个页面接受重定向的callback请求。
11.在Application.java页面加入以下代码:
@GetMapping("/callback")
public String callback() {
return "callback_page";
}
12.新建callback_page.html 文件,写入
<!DOCTYPE html>
<html>
<head><title>Insert title here</title></head>
<body>
Friends who has also granted client-implicit
<div id="friends">
<ul></ul>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function () {
//从url提取信息
var fragment = window.location.hash;
var res = getResponse(fragment);
window.location.hash = '_#';
if (res.hasError()) {
$("<div>Error trying to obtain user's authorization!</div>").insertBefore('#friends');
return;
}
getFriends(res['access_token'], function (friends) {
$(friends).each(function (index, friend) {
$('#friends').find('ul').append('<li>' + friend.name + '</li>');
});
});
});
/*]]>*/
//将信息分割成map
function getResponse(fragment) {
var attributes = fragment.slice(1).split('&');
var response = {};
$(attributes).each(function (idx, attr) {
var keyValue = attr.split('=');
response[keyValue[0]] = keyValue[1];
});
response.hasError = function () {
return !response['access_token'];
};
return response;
}
//拿到accessToken后,去资源中心拿资源
function getFriends(accessToken, callback) {
var baseUrl = 'https://graph.facebook.com/v2.9/';
var endpoint = 'me/friends';
var url = baseUrl + endpoint;
$.ajax({
url: url,
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
},
success: function (result) {
var friends = result.data;
callback(friends);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
}
});
}
</script>
</html>
How it Works……
在 facebook的验证环节中,Resource server和Authorization server的角色区分地并不是太明显,就像图中的OAuth2.0 Provider。
在上述步骤中,我们看到了客户端注册的三个步骤:
1) 选择client type.
2) 注册重定向路径(redirection url)
3) 输入应用信息
客户端注册成功后,我们拿到了client_id和client_secret,在上一个例子中,我们没用到密钥,因为是通过浏览器发送的,所以有泄漏的风险。因而,我们选择使用access token,来获取资源。Facebook 2.9有2个途径来通过Facebook Graph API 验证登录:
1)使用facebook SDK
2) 通过一个login请求流
我们选择了第二种方法,这就是我们刚才发送的请求流:
var request_endpoint = auth_endpoint + "?" +
"response_type=" + response_type + "&" +
"client_id=" + client_id + "&" +
"redirect_uri=" + encodeURI(redirect_uri) + "&" +
"scope=" + encodeURI(scope);
window.location.href = request_endpoint;
重定向到Authorization Server后,用户来进行验证,授权这个客户端app是否可以使用他的资源,一旦用户验证通过了,就会立刻重定向回之前输入的redirection url。当拿到access_token后,我们接下来要做的,就是运用Facebook Graph API 来拿到我们想要的资源。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。