欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Play 2.6 OAuth的使用

程序员文章站 2022-05-17 20:04:30
...

OAuth

https://playframework.com/documentation/2.6.x/JavaOAuth

OAuth是一个发布和交互受保护数据的简单方法。这是一种更加安全的访问方式。举个例子,你可以去获取用户在Twitter上的数据。

OAuth有两个版本,1.02.0。第二个版本在不使用类库的情况下也很容易实现。因此Play只对1.0版本进行了支持。

使用

添加依赖

libraryDependencies ++= Seq(
  ws
)

需要的信息

OAuth需要你在服务提供商进行注册。确保检查你的回调URL,当不匹配是服务提供商有可能会拒绝你的调用。当在本地工作时,可以使用/etc/hosts/来伪造一个本地机器的域名

服务提供商会提供:
- Application ID
- Secret key
- Request Token URL
- Access Token URL
- Authorize URL

认证流程

大部分流程都会由Play类库来完成
1. 从服务端获取request token(在服务端到服务端的调用中)
2. 将用户重定向到服务提供商,这里用户会对你的应用进行授权
3. 服务提供商会将用户重定向返回,并提供一个verifier
4. 根据verifier,交换request token和access token
access token可以传递给任何需要获取保护数据的请求。

可以在The OAuth Bible获取更多细节。

Example

conf/routers

GET     /twitter/homeTimeline controllers.Twitter.homeTimeline()
GET     /twitter/auth         controllers.Twitter.auth()

controller

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.Result;

import com.google.common.base.Strings;

import javax.inject.Inject;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

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() {
        Optional<RequestToken> sessionTokenPair = getSessionTokenPair();
        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() {
        String verifier = request().getQueryString("oauth_verifier");
        if (Strings.isNullOrEmpty(verifier)) {
            String url = routes.Twitter.auth().absoluteURL(request());
            RequestToken requestToken = TWITTER.retrieveRequestToken(url);
            saveSessionTokenPair(requestToken);
            return redirect(TWITTER.redirectUrl(requestToken.token));
        } else {
            RequestToken requestToken = getSessionTokenPair().get();
            RequestToken accessToken = TWITTER.retrieveAccessToken(requestToken, verifier);
            saveSessionTokenPair(accessToken);
            return redirect(routes.Twitter.homeTimeline());
        }
    }

    private void saveSessionTokenPair(RequestToken requestToken) {
        session("token", requestToken.token);
        session("secret", requestToken.secret);
    }

    private Optional<RequestToken> getSessionTokenPair() {
        if (session().containsKey("token")) {
            return Optional.ofNullable(new RequestToken(session("token"), session("secret")));
        }
        return Optional.empty();
    }

}
OAuth不能抵御任何MITM攻击(https://en.wikipedia.org/wiki/Man-in-the-middle_attack)。这个例子中将token和secret保存到会话cookie中,通过play.http.session.secure=true配置来启用https来获取最好的保护。