§OAuth
OAuth 是一种简单的方式来发布和交互受保护的数据。它也是人们授予您访问权限的更安全、更可靠的方式。例如,它可以用于访问您用户在 Twitter 上的数据。
OAuth 有两个截然不同的版本:OAuth 1.0 和 OAuth 2.0。版本 2 足够简单,可以在没有库或帮助程序的情况下轻松实现,因此 Play 仅提供对 OAuth 1.0 的支持。
§用法
要使用 OAuth,首先将 ws
添加到您的 build.sbt
文件中
libraryDependencies ++= Seq(
javaWs
)
§所需信息
OAuth 要求您将应用程序注册到服务提供商。请务必检查您提供的回调 URL,因为如果它们不匹配,服务提供商可能会拒绝您的调用。在本地工作时,您可以使用 /etc/hosts
在本地机器上伪造一个域。
服务提供商将为您提供
- 应用程序 ID
- 密钥
- 请求令牌 URL
- 访问令牌 URL
- 授权 URL
§身份验证流程
大部分流程将由 Play 库完成。
- 从服务器获取请求令牌(在服务器到服务器的调用中)
- 将用户重定向到服务提供商,用户将在那里授予您的应用程序使用其数据的权限
- 服务提供商将把用户重定向回来,为您提供一个 /验证器/
- 使用该验证器,将 /请求令牌/ 交换为 /访问令牌/(服务器到服务器的调用)
现在,/访问令牌/ 可以传递给任何访问受保护数据的调用。
有关 OAuth 流程的更多详细信息,请访问 OAuth 圣经。
§示例
conf/routes
:
GET /twitter/homeTimeline controllers.Twitter.homeTimeline(request: Request)
GET /twitter/auth controllers.Twitter.auth(request: Request)
控制器
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import javax.inject.Inject;
import play.libs.oauth.OAuth;
import play.libs.oauth.OAuth.ConsumerKey;
import play.libs.oauth.OAuth.OAuthCalculator;
import play.libs.oauth.OAuth.RequestToken;
import play.libs.oauth.OAuth.ServiceInfo;
import play.libs.ws.WSClient;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
public class Twitter extends Controller {
static final ConsumerKey KEY = new ConsumerKey("...", "...");
private static final ServiceInfo SERVICE_INFO =
new ServiceInfo(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize",
KEY);
private static final OAuth TWITTER = new OAuth(SERVICE_INFO);
private final WSClient ws;
@Inject
public Twitter(WSClient ws) {
this.ws = ws;
}
public CompletionStage<Result> homeTimeline(Http.Request request) {
Optional<RequestToken> sessionTokenPair = getSessionTokenPair(request);
if (sessionTokenPair.isPresent()) {
return ws.url("https://api.twitter.com/1.1/statuses/home_timeline.json")
.sign(new OAuthCalculator(Twitter.KEY, sessionTokenPair.get()))
.get()
.thenApply(result -> ok(result.asJson()));
}
return CompletableFuture.completedFuture(redirect(routes.Twitter.auth()));
}
public Result auth(Http.Request request) {
Optional<String> verifier = request.queryString("oauth_verifier");
Result result =
verifier
.filter(s -> !s.isEmpty())
.map(
s -> {
RequestToken requestToken = getSessionTokenPair(request).get();
RequestToken accessToken = TWITTER.retrieveAccessToken(requestToken, s);
return redirect(routes.Twitter.homeTimeline())
.addingToSession(request, "token", accessToken.token)
.addingToSession(request, "secret", accessToken.secret);
})
.orElseGet(
() -> {
String url = routes.Twitter.auth().absoluteURL(request);
RequestToken requestToken = TWITTER.retrieveRequestToken(url);
return redirect(TWITTER.redirectUrl(requestToken.token))
.addingToSession(request, "token", requestToken.token)
.addingToSession(request, "secret", requestToken.secret);
});
return result;
}
private Optional<RequestToken> getSessionTokenPair(Http.Request request) {
return request
.session()
.get("token")
.map(token -> new RequestToken(token, request.session().get("secret").get()));
}
}
注意:OAuth 无法提供针对 中间人攻击 的任何保护。此示例显示了存储在会话 cookie 中的 OAuth 令牌和密钥 - 为了获得最佳安全性,请始终使用 HTTPS 并定义
play.http.session.secure=true
。
下一步:与 Pekko 集成
在此文档中发现错误?此页面的源代码可以在 此处 找到。阅读完 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?访问 我们的社区论坛 与社区开始对话。