在Play(Java)中实现OAuth2的密码所有者资源流

时间:2018-06-19 15:41:18

标签: java playframework oauth-2.0 authorization

对于我的学士论文,我必须使用不同的框架来实现不同种类的身份验证和授权。 目前,我在OAuth2一章中讲过,必须在Play框架(Java)中实现它。 (我已经用Spring Boot实现了它) 到目前为止,在研究如何解决此问题时,我找不到很多有用的提示。

我要提出的主要问题之一是:客户端使用用户凭据对自身进行身份验证并获得令牌后,如何最好地验证令牌? 基本上:Spring的“ @PreAuthorize”注解的Play对应物是什么?

任何提示或指向有用网站的链接都将受到赞赏。

提前坦克!

1 个答案:

答案 0 :(得分:0)

所以我想我解决了我的问题。如果有人偶然发现相同的问题,我将在此处发布解决方案:

使用OAuth2,尤其是使用密码流,在Play文档(https://www.playframework.com/documentation/2.6.x/JavaOAuth)中编写,这非常简单。

首先,您需要一个Authorization-Service,此处的实现很简单。只需实现三种方法:

POST / oauth / token用于传递用户凭证并接收访问令牌和刷新令牌

POST / oauth / refrefsh,表示访问令牌不再有效。这里传递了刷新令牌,并返回了新的acces令牌

POST / oauth / check_token进行授权。这里传递了访问令牌,在我的情况下,我返回了用户的角​​色。或者,也可以在授权服务中进行授权过程,甚至可能更好。为此,您需要更改“ check_token”方法并传递所需的角色。

我只是将uuid生成为令牌,并将它们存储在数据库中。我猜也可以使用例如jwts并将所需的信息(例如到期日期)放入令牌中。

然后我的主要问题是关于注释。我找到了这个 https://github.com/bekce/oauthly 然后看看它们的实现。

您基本上只需要一个类和一个接口:

界面:

@With(AuthorizationServerAuthAction.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorizationServerSecure {
    boolean requireAdmin() default false;
    boolean requirePersonnel() default false;
    boolean requireGuest() default false;
}

班级:

private WSClient ws;
private final String url = "http://localhost:9001/oauth/check_token";
@Inject
public AuthorizationServerAuthAction(WSClient ws) {
    this.ws = ws;
}

private CompletionStage<JsonNode> callApi(String accessToken) {
    CompletionStage<WSResponse> eventualResponse =  ws.url(url).setContentType("application/x-www-form-urlencoded").setRequestTimeout(Duration.ofSeconds(10))
            .addHeader("Authorization" ,  accessToken).post("none");
    return eventualResponse.thenApply(WSResponse::asJson);
}
@Override
public CompletionStage<Result> call(Http.Context ctx) {
    Optional<String> accessTokenOptional = ctx.request().header("Authorization");
    JsonNode result = null;
    if(!accessTokenOptional.isPresent()){
        return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                .put("message", "No token found in header!")
        ));
    }

    CompletionStage<JsonNode> apiResponse = callApi(accessTokenOptional.get());
    try {
        result = apiResponse.toCompletableFuture().get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    if(result == null) {
        return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                .put("message", "an error occurred")
        ));
    }
    String role = result.get("role").asText();

    if(configuration.requireAdmin()){
        if(role.equals("admin")) {
            return delegate.call(ctx);
        } else {
            return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                    .put("message", "The user is not authorized to perform this action!")
            ));
        }
    } else if(configuration.requirePersonnel()) {
        if(role.equals("personnel") || role.equals("admin")) {
            return delegate.call(ctx);
        } else {
            return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                    .put("message", "The user is not authorized to perform this action!")
            ));
        }
    } else if(configuration.requireGuest()) {
        if(role.equals("guest") || role.equals("personnel") || role.equals("admin")) {
            return delegate.call(ctx);
        } else {
            return CompletableFuture.completedFuture(unauthorized(Json.newObject()
                    .put("message", "The user is not authorized to perform this action!")
            ));
        }
    }
    return CompletableFuture.completedFuture(unauthorized(Json.newObject()
            .put("message", "an error occurred")
    ));

}

}