简体   繁体   English

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

[英]Implementing the password owner resource flow of OAuth2 in Play (Java)

For my Bachelor's-thesis I have to implement different kinds of Authentication and Authorization with different Frameworks. 对于我的学士论文,我必须使用不同的框架来实现不同种类的身份验证和授权。 Currently im at the OAuth2 chapter and have to implement it in the Play Framework (in Java). 目前,我在OAuth2一章中讲过,必须在Play框架(Java)中实现它。 (I have already implemented it with Spring Boot) While researching on how to approach this Problem, so far, I could not find a lot of helpful tips. (我已经使用Spring Boot实现了它)到目前为止,在研究如何解决此问题时,我找不到很多有用的技巧。

One of the main Questions I have is: after the Client authenticatet itselfe with the users credentials and has gotten the Token, how do I best verify the Token? 我的主要问题之一是:在客户端使用用户凭据对自身进行身份验证并获得令牌后,如何最好地验证令牌? Basicly: What is the Play- counterpart to the "@PreAuthorize" annotation of Spring? 基本上:Spring的“ @PreAuthorize”注释的Play对应部分是什么?

Any tip or link to a helpful website is appreciated. 任何提示或链接到有用的网站表示赞赏。

So I think I solved my Problem. 所以我想我解决了我的问题。 On the off chance that someone stumbles on the same question I'm gonna post the solution here: 如果有人偶然发现相同的问题,我将在此处发布解决方案:

As written in the Play-Docs ( https://www.playframework.com/documentation/2.6.x/JavaOAuth ) with OAuth2 and especially with the Password flow it is pretty simple. 正如使用OAuth2(尤其是使用密码流)在Play文档( https://www.playframework.com/documentation/2.6.x/JavaOAuth )中编写的那样,它非常简单。

First you need an Authorization-Service, here the implementation is straight forward. 首先,您需要一个Authorization-Service,这里的实现很简单。 Just implement three methods: 只需实现三种方法:

POST /oauth/token for passing the user-credentials and recieving an access- and refresh-token POST / oauth / token用于传递用户凭证并接收访问令牌和刷新令牌

POST /oauth/refresh for when the access-token is no longer valid. 当访问令牌不再有效时,POST / oauth / refresh。 Here the refresh-token is passed and a new acces token returned 这里传递了刷新令牌,并返回了新的acces令牌

POST /oauth/check_token for authorization. POST / oauth / check_token进行授权。 Here the access Token is passed and in my case I return the role, the user has. 这里传递了访问令牌,在我的情况下,我返回了用户的角​​色。 Alternativly it would also be possible and maybe eaven better to do the authorization process in the authorization-service. 或者,也可以在授权服务中进行授权过程,甚至可能更好。 For this you would need to change the "check_token" method and pass the required role. 为此,您需要更改“ check_token”方法并传递所需的角色。

I just generated uuids as tokens and stored them in a database. 我只是将uuid生成为令牌,并将它们存储在数据库中。 I guess one could also use for example jwts and put the needed information (for example the expiration date) in the token. 我猜也可以使用例如jwts并将所需的信息(例如到期日期)放入令牌中。

Then my main question was about the annotations. 然后我的主要问题是关于注释。 I found this https://github.com/bekce/oauthly and just lookt at their implementation. 我找到了这个https://github.com/bekce/oauthly ,只是看一下它们的实现。

You basicly just need a class and a interface: 您基本上只需要一个类和一个接口:

The Interface: 接口:

@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;
}

The Class: 班级:

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")
    ));

}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM