authentication - 在Jersey Jax-rs Web服务上启用OAuth1支持

标签 authentication oauth oauth-2.0 jersey jax-rs

我想在我 Restful Web服务上启用OAuth1提供程序支持。 Jersey支持此功能,如 Jersey OAuth1 Provider support所述。
我一直在尝试将其注册为:

public ApplicationConfig(){
    super();
    addRestResourceClasses(getMyResourceClasses());                 
    register(new OAuth1ServerFeature(new DefaultOAuth1Provider(),"/oauth/access_token","/oauth/request_token"));
}

但是,当我注册OAuth1ServerFeature时,尝试访问我的资源时得到404。
似乎在任何地方都找不到实现jersey oauth支持的示例/教程!

我可以插入jax-rs服务中以启用oauth支持的简单组件吗?

最佳答案

我知道该线程有些陈旧-但是自己完成该工作后,我觉得应该按顺序进行回复!如果有时间,我什至可以用更完整的示例创建博客文章。请注意-这不是一个简短的答案!

绝对缺乏有关使用 Jersey OAuth1服务器(也称为Provider)功能的信息的示例-我不记得一个技术主题透露了很少的有用Google信息。我几乎继续寻找另一种解决方案,因为它使我认为它可能无法正常工作。但是,只要有一定的毅力,我可以说它不仅可以使用,而且看起来还不错。另外,当然,如果您已经将Jersey用于REST API,则不需要任何额外的库。

我不是OAuth1专家-我强烈建议尝试此操作的读者阅读一些背景知识。我还假设您在使用Jersey,了解ContainerRequestFilters之类的内容,并且还具有一些内部方法来授权用户。

我的示例还使用了出色的JAX-RS OSGi连接器-唯一的真正区别是,在我们使用OSGi包上下文通过OSGI服务注册OAuth1功能的情况下,常规的Jersey用户将需要通过其常规的Application/Server配置模型进行配置。

初始化

您必须创建OAuth1功能-并为其提供一个提供程序:

DefaultOAuth1Provider oap = new DefaultOAuth1Provider();
Feature oaFeature = new OAuth1ServerFeature(oap, "oauth1/request_token", "oauth1/access_token");       

不要忘记在 Jersey 注册oaFeature!

DefaultOAuth1Provider完全基于内存-这对我们来说很好。许多人会希望保留访问 token 以在服务器重新启动期间使用,这将需要扩展的子类(或干净的实现)

添加您的消费者 key 和 secret

我花了一段时间才意识到,消费者不是用户,而是客户,即应用程序。如果您没有为希望连接的每个消费者(也称为客户端应用)注册 key 和 secret ,则Jersey实现将无法正常工作
oap.registerConsumer("some-owner-id", 
                      "abcdef" ,
                      "123456",
                      new MultivaluedHashMap<String,String> ());

您显然永远不会对它们进行硬编码,并且会进一步使用某种形式的安全存储来存储 secret (参数3)。

如果您不添加这些内容,那么您将一无所获。

OAuth协议(protocol)步骤1-获取请求 token

在此阶段,您已经准备好客户端获取请求 token -此处有一个perfectly good example on GitHub
ConsumerCredentials consumerCredentials = new ConsumerCredentials("abcdef","123456");

//TODO - user proper client builder with real location + any ssl context
OAuth1AuthorizationFlow authFlow = OAuth1ClientSupport.builder(consumerCredentials)
            .authorizationFlow(
                    "http://myhost:8080/myapi/oauth1/request_token",
                    "http://myhost:8080/myapi/oauth1/access_token",
                    "http://myhost:8080/myapi/oauth1/authorize")
            .build();
String authorizationUri = authFlow.start();
System.out.println("Auth URI: " + authorizationUri); 

显然,您将更改URL以指向您的服务器,并且-至关重要的是-客户端需要使用与在服务器中注册的相同的Conumer Key和Secret。

您将返回其中包含oauth_token字符串的响应,例如
http://myhost:8080/myapi/oauth/authorize?oauth_token=a1ec37598da
b47f6b9d770b1b23a5f99

OAuth协议(protocol)第2步-授权用户

就像您在任何文章中都会读到的那样,实际的用户授权不在OAuth1的范围内-在此阶段,无论如何,您都必须调用服务器身份验证过程。

然而!!!!如果用户成功授权,则服务器需要执行的操作不在OAuth1范围之内。您必须告知DefaultOAuth1Provider成功的身份验证:
// Dummy code - make out like we're auth'd
Set<String> dummyRoles = new HashSet<> (Arrays.asList( new String[] { "my-role-1", "my-role-2" }));
DefaultOAuth1Provider.Token tok1 = getRequestToken("a1ec37598da
b47f6b9d770b1b23a5f99");
String verifier = authorizeToken(tok1, new Principal()
            {
                public String getName()
                {
                    return "my-user";
                }
            }, 
            dummyRoles);
System.out.println("***** verifier: " + verifier);

请注意,请求 token 字符串是从步骤1开始的。显然,实际的实现将为授权用户传递真实的Principal和角色集。

同样,当然,打印出验证程序并没有太大用处-您需要以某种方式(通过独立 channel 或作为身份验证响应中的 header )将其返回给客户端-可能需要对其进行加密以用于增加了保护。

OAuth协议(protocol)步骤3-将请求 token 交换为访问 token

客户端收到或手动输入验证者后,便可以完成流程并将请求 token 交换为访问 token ,例如
String verifier = System.console().readLine("%s", "Verifier: ");
final AccessToken accessToken = authFlow.finish(verifier);        
System.out.println("Access token: " + accessToken.getToken());      

同样,这不是一个现实的例子-但它显示了该过程。

如果您的OAuth1Provider将访问 token 保存到服务器上的某个持久性存储中,则可以在以后的 session 中重复使用此处返回的所有访问 token ,而无需执行所有前面的步骤。

就是这样-然后,您只需要确保客户端从此刻起在流程中创建的每个请求都使用该访问 token 即可。

关于authentication - 在Jersey Jax-rs Web服务上启用OAuth1支持,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21798855/

相关文章:

c# - 具有 Azure Active Directory 的 Web 应用程序始终重定向到 '~/.auth/login/done' URL

php - 如何在 PHP 中创建一个非常简单的用户名-密码登录?

java - client_secrets.json 文件必须放在 Android Studio 项目文件夹树中的什么位置?

javascript - 如何在没有重定向 url 的情况下验证 instagram?没有服务器

node.js - 使用 OAuth 2.0 进行服务器到服务器应用程序的 Node

python - Django:用户登录系统与用户注册不在同一页面中工作

c++ - 凭据提供程序的自定义 GUI

java - Google Directory API 仅针对 ADMIN_DIRECTORY_ORGUNIT 提供 401 服务帐户

security - 如何在 Haskell 中对字符串的 SHA256 哈希进行 Base64 UrlEncode?

javascript - chrome.identity.launchwebauthflow 对于特定用户失败