3.9.11.3.1. REST API 中的社交账号登录
社交账号登录的机制也可以在 REST API 中使用。完整的示例应用程序可以在 GitHub 上找到,同时在社交网站登录部分有详细描述,下面是使用 Facebook 帐户获取访问令牌的关键点。
- 在 web 模块的根包下创建
restapi
包,并在其中实现自定义 Spring MVC 控制器。该控制器应包含两个主要方法:get()
方法获取ResponseEntity
实例,login()
方法获取 OAuth 令牌。
FacebookAuthenticationController.java
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity get() {
String loginUrl = getAsPrivilegedUser(() ->
facebookService.getLoginUrl(getAppUrl(), OAuth2ResponseType.CODE_TOKEN)
);
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.LOCATION, loginUrl);
return new ResponseEntity<>(headers, HttpStatus.FOUND);
}
在这里,我们检查 Facebook code,获取访问代码并使用 OAuthTokenIssuer
发出访问令牌:
FacebookAuthenticationController.java
@RequestMapping(method = RequestMethod.POST, value = "login")
public ResponseEntity<OAuth2AccessToken> login(@RequestParam("code") String code) {
User user = getAsPrivilegedUser(() -> {
FacebookUserData userData = facebookService.getUserData(getAppUrl(), code);
return socialRegistrationService.findOrRegisterUser(
userData.getId(), userData.getEmail(), userData.getName());
});
OAuth2AccessTokenResult tokenResult = oAuthTokenIssuer.issueToken(user.getLogin(),
messageTools.getDefaultLocale(), Collections.emptyMap());
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CACHE_CONTROL, "no-store");
headers.set(HttpHeaders.PRAGMA, "no-cache");
return new ResponseEntity<>(tokenResult.getAccessToken(), headers, HttpStatus.OK);
}
- 从 web/core 模块扫描中排除
restapi
包:OAuthTokenIssuer
bean 仅在 REST API 上下文中可用,在应用程序上下文中对其进行扫描将导致错误。
<context:component-scan base-package="com.company.demo">
<context:exclude-filter type="regex" expression="com\.company\.demo\.restapi\..*"/>
</context:component-scan>
- 在项目的
modules/web/web/VAADIN
文件夹中创建facebook-login-demo.html
文件,包含在 HTML 页面上运行的 JavaScript 代码:
<html>
<head>
<title>Facebook login demo with REST-API</title>
<script src="jquery-3.2.1.min.js"></script>
<style type="text/css">
#users { display: none; }
</style>
</head>
<body>
<h1>Facebook login demo with REST-API</h1>
<script type="application/javascript"...>
</script>
<a id="fbLink" href="/app/rest/facebook">Login with Facebook</a>
<div id="users">
You are logged in!
<h1>Users</h1>
<div id="usersList">
</div>
</div>
</body>
</html>
以下脚本将尝试使用 Facebook 登录。首先,它将从 URL 中删除 code 参数,然后它将 code 传递给 REST API 以获取 OAuth 访问令牌,在成功验证的情况下,将能够正常加载和保存数据。
var oauth2Token = null;
function tryToLoginWithFacebook() {
var urlHash = window.location.hash;
if (urlHash && urlHash.indexOf('&code=') >= 0) {
console.log("Try to login to CUBA REST-API!");
var urlCode = urlHash.substring(urlHash.indexOf('&code=') + '&code='.length);
console.log("Facebook code: " + urlCode);
history.pushState("", document.title, window.location.pathname);
$.post({
url: '/app/rest/facebook/login',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
dataType: 'json',
data: {code: urlCode},
success: function (data) {
oauth2Token = data.access_token;
loadUsers();
}
})
}
}
function loadUsers() {
$.get({
url: '/app/rest/v2/entities/sec$User?view=_local',
headers: {
'Authorization': 'Bearer ' + oauth2Token,
'Content-Type': 'application/x-www-form-urlencoded'
},
success: function (data) {
$('#fbLink').hide();
$('#users').show();
$.each(data, function (i, user) {
$('#usersList').append("<li>" + user.name + " (" + user.email + ")</li>");
});
}
});
}
tryToLoginWithFacebook();
另一个示例或在 CUBA 应用程序中运行 JavaScript 代码,可以在JavaScript 用法示例部分找到。