java 尝试在 Spring MVC 中使用 OAuth 保护资源
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5431359/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Trying to protect resources with OAuth in Spring MVC
提问by Ben Burns
We already have REST web services written in Java on Spring MVC and I have been trying to protect them.
我们已经在 Spring MVC 上使用 Java 编写了 REST Web 服务,我一直在努力保护它们。
The OAuth server is implemented in another website which handles the logging in and creation of the Access Token. I need therefore to verify that the access token is correct before giving the users access to the webservices.
OAuth 服务器在另一个网站中实现,该网站处理访问令牌的登录和创建。因此,在授予用户访问网络服务的权限之前,我需要验证访问令牌是否正确。
However the documentation for Spring Security with OAuth seems to be really poor, and the example code doesn't actually explain what it is doing! I am not even sure if I should be implementing it for this, as it should be such a simple check.
然而,带有 OAuth 的 Spring Security 的文档似乎非常糟糕,示例代码实际上并没有解释它在做什么!我什至不确定我是否应该为此实施它,因为它应该是一个如此简单的检查。
What is the best way to go about protecting these web services? And what is the best way to get started?
保护这些 Web 服务的最佳方法是什么?什么是最好的开始方式?
Thanks for you help.
谢谢你的帮助。
回答by Ben Burns
Important
重要的
[Edit 12/27/2012: The tutorial I reference below is now throwing a 404. There is a slightly updated version of this tutorial on github. I've struck throughthe links which appear to be bad. For now I'm leaving this as-is for posterity since the now-missing tutorial is the one referenced by the asker. To the best of my knowledge, the information contained herein is still useful, so maybe someday when I have time I'll rewrite it against the new tutorial.]
[编辑 12/27/2012:我在下面参考的教程现在抛出 404。在 github 上有一个稍微更新的版本。我已经浏览了看起来很糟糕的链接。现在我将这个原样留给后人,因为现在丢失的教程是提问者引用的教程。 据我所知,这里包含的信息仍然有用,所以也许有一天我有时间根据新教程重写它。]
This answer assumes that by "The OAuth server is implemented in another website which handles the logging in and creation of the Access Token." You mean that you are consuming a service on a separate site that is not your own.
此答案假设“OAuth 服务器是在另一个处理访问令牌的登录和创建的网站中实现的”。您的意思是您在不属于您自己的单独站点上使用服务。
Background
背景
I can certainly relate to your documentation woes. Spring Security has arguably the steepest learning curve of any Spring project, and OAuth support is fairly new and maintained separately from Spring Security. The Spring Security OAuth docs aresparse.
我当然可以与您的文档问题有关。Spring Security 可以说是所有 Spring 项目中最陡峭的学习曲线,并且 OAuth 支持是相当新的,并且与 Spring Security 分开维护。春季安全的OAuth文档是稀疏。
If you don't have a good feel for OAuth, go get one!You are asking your users to trust the security of your site's implementation of this standard. As such, you cannot afford any ambiguity in your understanding of the subject! The obvious place to start is OAuth.netand the OAuth Beginner's Guideat huniverse.
如果您对 OAuth 没有很好的感觉,那就去买一个吧!您要求您的用户信任您的站点实施此标准的安全性。因此,您对这个主题的理解不能有任何歧义!显而易见的起点是OAuth.net和huniverse的OAuth 初学者指南。
If/Once you have a good feel for how OAuth works, I'd highly recommend reading through the Spring Security "Getting Started" and "Articles and Tutorials" documentation lists to get a good feel for how Spring Security is implemented in general.
如果/一旦您对 OAuth 的工作原理有了很好的了解,我强烈建议您通读 Spring Security 的“入门”和“文章和教程”文档列表,以便对 Spring Security 的总体实现方式有一个很好的了解。
Once you have a decent knowledge of Spring Security and a decent knowledge of OAuth, the official Spring Security OAuth user guidewill start to make sense. You'll want to pay attention particularly the Consumer/Client sections for the version of OAuth you're working with (1.0or 2.0).
一旦您对 Spring Security 有一定的了解,并且对 OAuth 有一定的了解,官方的 Spring Security OAuth用户指南就会开始变得有意义。您需要特别注意您正在使用的 OAuth 版本(1.0或2.0)的 Consumer/Client 部分。
That same site also has a decent tutorialfor both OAuth 1.0 and OAuth 2.0 which is based on the second section of the services OAuth Beginner's Guidementioned above.
同一个站点还有一个不错的OAuth 1.0 和 OAuth 2.0教程,该教程基于上述服务OAuth 初学者指南的第二部分。
Accessing Protected Restful Resources
访问受保护的 Restful 资源
For your problem we're going to focus on the implementation of the Tonr photo printing service from the tutorialmentioned above. This service prints photos which are OAuth protected resources hosted by external sites. Tonr defers to these sites for access control of these resources. This will include redirecting the user for user authentication and authentication confirmation if necessary.
对于您的问题,我们将重点关注上述教程中Tonr 照片打印服务的实现。此服务打印照片,这些照片是由外部站点托管的受 OAuth 保护的资源。Tonr 遵从这些站点对这些资源的访问控制。这将包括在必要时重定向用户以进行用户身份验证和身份验证确认。
Spring-MVC REST services/controllers which are themselves consumers of external OAuth protected resources implement this "deferred authorization" (my term) behavior through the use of request filters. Per the 1.0 user guide:
Spring-MVC REST 服务/控制器本身就是外部 OAuth 保护资源的消费者,它们通过使用请求过滤器来实现这种“延迟授权”(我的术语)行为。根据 1.0用户指南:
There are two request filters that are applicable to the OAuth consumer logic. The first filter, OAuthConsumerContextFilter, is responsible for establishing an OAuth-specific security context, very similar to Spring Security's SecurityContext. The security context simply contains a set of access tokens that have been obtained for the current user. This security context is leveraged when making requests for protected resources.
There is another request filter, OAuthConsumerProcessingFilter, that can be applied to specific URLs or URL patterns that require access to a remote protected resource. Putting this filter in Spring Security's filter chain will ensure that any access tokens needed for the specified URL patters will be obtained before allowing access to the resources.
有两个请求过滤器适用于 OAuth 使用者逻辑。第一个过滤器 OAuthConsumerContextFilter负责建立特定于 OAuth 的安全上下文,与 Spring Security 的SecurityContext非常相似 。安全上下文仅包含为当前用户获取的一组访问令牌。在请求受保护资源时会利用此安全上下文。
还有另一个请求过滤器 OAuthConsumerProcessingFilter,可应用于需要访问远程受保护资源的特定 URL 或 URL 模式。将此过滤器放在 Spring Security 的过滤器链中将确保在允许访问资源之前获得指定 URL 模式所需的任何访问令牌。
So as you can see, for OAuth 1.0, filtering requests with a valid OAuthConsumerProcessingFilter
will handle everything surrounding acquiring valid Access Tokens, as well as notifying the user when access is denied. Likewise there is are corresponding OAuth2ClientContextFilter
and OAuth2ClientProcessingFilter
classes.
如您所见,对于 OAuth 1.0,使用有效过滤请求OAuthConsumerProcessingFilter
将处理与获取有效访问令牌相关的所有事情,并在访问被拒绝时通知用户。同样有对应的OAuth2ClientContextFilter
和OAuth2ClientProcessingFilter
类。
Finally, once this is all set up you can access OAuth protected resources in your controllers with OAuthRestTemplate
or OAuth2RestTemplate
just like you would access unprotected resources with the normal RestTemplate
(info here). However they must be injected into your service or controller with an instance of ProtectedResourceDetailsor OAuth2ProtectedResourceDetails.
最后,一旦这一切都设置好,您就可以访问控制器中受 OAuth 保护的资源,OAuthRestTemplate
或者OAuth2RestTemplate
就像您使用正常访问不受保护的资源一样RestTemplate
(信息在这里)。但是,它们必须通过ProtectedResourceDetails或OAuth2ProtectedResourceDetails实例注入到您的服务或控制器中。
I have good news if this sounds complex. All of this nonsense is typically abstracted away and handled for you by the OAuth and OAuth2 XML Namespaces
如果这听起来很复杂,我有个好消息。所有这些废话通常都由 OAuth 和 OAuth2 XML 命名空间抽象出来并为您处理
The oauth namespace is demonstrated in the Tonr tutorials' XML config files located in their respective src/webapp/WEB-INF directories. The examples below are abbreviated directly from there.
oauth 命名空间在 Tonr 教程的 XML 配置文件中演示,该文件位于各自的 src/webapp/WEB-INF 目录中。下面的例子直接从那里缩写。
If you'd like to see how the provider side works withoutusing OAuth namespaces, I'd suggest you check this SpringSource forum post, and follow the issue SECOAUTH-53for updates.
如果您想了解提供方如何在不使用 OAuth 命名空间的情况下工作,我建议您查看此 SpringSource 论坛帖子,并关注问题SECOAUTH-53以获取更新。
OAuth 1.0 Example
OAuth 1.0 示例
Tonr is consuming OAuth protected services from both Sparklr and Google here, so it sets up a ProtectedResourceDetailsService
called resourceDetails
using the oauth:resource-details-service
tag. It then sets up the OAuthConsumerContextFilter
and OAuthConsumerProcessingFilter
with a reference to resourceDetails
by using the oauth:consumer
tag. These filters are created with instances of ProtectedResourceDetails
for each of the protected resource providers by using the oauth:resource
tag.
Tonr 正在使用来自 Sparklr 和 Google 的 OAuth 保护服务,因此它使用标签设置了一个ProtectedResourceDetailsService
调用。然后它通过使用标记设置和并引用。这些过滤器是使用标记为每个受保护资源提供程序创建的实例。resourceDetails
oauth:resource-details-service
OAuthConsumerContextFilter
OAuthConsumerProcessingFilter
resourceDetails
oauth:consumer
ProtectedResourceDetails
oauth:resource
From tonr's applicationContext.xml:
来自 tonr 的 applicationContext.xml:
<oauth:consumer resource-details-service-ref="resourceDetails" oauth-failure-page="/oauth_error.jsp">
<oauth:url pattern="/sparklr/**" resources="sparklrPhotos"/>
<oauth:url pattern="/google/**" resources="google"/>
</oauth:consumer>
<oauth:resource-details-service id="resourceDetails">
<oauth:resource id="sparklrPhotos"
key="tonr-consumer-key"
secret="SHHHHH!!!!!!!!!!"
request-token-url="http://localhost:8080/sparklr/oauth/request_token"
user-authorization-url="http://localhost:8080/sparklr/oauth/confirm_access"
access-token-url="http://localhost:8080/sparklr/oauth/access_token"/>
<!--see http://code.google.com/apis/accounts/docs/OAuth_ref.html-->
<oauth:resource id="google" key="anonymous" secret="anonymous"
request-token-url="https://www.google.com/accounts/OAuthGetRequestToken"
user-authorization-url="https://www.google.com/accounts/OAuthAuthorizeToken"
access-token-url="https://www.google.com/accounts/OAuthGetAccessToken"
request-token-method="GET"
access-token-method="GET">
<oauth:addtionalParameter name="scope" value="https://picasaweb.google.com/data/"/>
<oauth:addtionalParameter name="xoauth_displayname" value="Tonr Example Application"/>
</oauth:resource>
</oauth:resource-details-service>
Next the sparklrService
and googleService
beans are created, each with their own internal OAuthRestTemplate
bean, each which is provided with a reference via constructor-arg
to the respective ProtectedResourceDetails
which were created previously and injected into the ProtectedResourceDetailsService
bean.
接下来创建sparklrService
和googleService
bean,每个OAuthRestTemplate
bean 都有自己的内部bean,每个 bean 都通过constructor-arg
对ProtectedResourceDetails
先前创建并注入ProtectedResourceDetailsService
bean的各自的引用提供。
From tonr's spring-servlet.xml:
来自 tonr 的 spring-servlet.xml:
<bean id="sparklrService" class="org.springframework.security.oauth.examples.tonr.impl.SparklrServiceImpl">
<property name="sparklrPhotoListURL" value="${sparklrPhotoListURL}"/>
<property name="sparklrPhotoURLPattern" value="${sparklrPhotoURLPattern}"/>
<property name="sparklrRestTemplate">
<bean class="org.springframework.security.oauth.consumer.OAuthRestTemplate">
<constructor-arg ref="sparklrPhotos"/>
</bean>
</property>
</bean>
<bean id="googleService" class="org.springframework.security.oauth.examples.tonr.impl.GoogleServiceImpl">
<property name="googleRestTemplate">
<bean class="org.springframework.security.oauth.consumer.OAuthRestTemplate">
<constructor-arg ref="google"/>
</bean>
</property>
</bean>
OAuth 2.0 Example
OAuth 2.0 示例
My understanding is a little bit weaker here.Part of the reason for this is that the OAuth2 namespace appears to abstract away a lot more. Also, it looks like the Tonr 2 example hasn't been fleshed out as well as the original Tonr example. I'll do my best and edit if necessary.
我的理解在这里有点弱。部分原因是 OAuth2 命名空间似乎抽象了很多。此外,看起来 Tonr 2 示例没有像原始 Tonr 示例那样充实。我会尽我所能并在必要时进行编辑。
First an oauth:client
tag is created and given a reference to an InMemoryOAuth2ClientTokenServices
bean. It appears that this sets up the appropriate filters. Then OAuth2ProtectedResourceDetails
beans are created for both sparklr and Facebook with the oauth:resource
.
首先oauth:client
创建一个标签并提供对InMemoryOAuth2ClientTokenServices
bean的引用。这似乎设置了适当的过滤器。然后OAuth2ProtectedResourceDetails
使用oauth:resource
.
From tonr 2's applicationContext.xml:
来自 tonr 2 的 applicationContext.xml:
<!--apply the oauth client context-->
<oauth:client token-services-ref="oauth2TokenServices"/>
<beans:bean id="oauth2TokenServices" class="org.springframework.security.oauth2.consumer.token.InMemoryOAuth2ClientTokenServices"/>
<!--define an oauth 2 resource for sparklr-->
<oauth:resource id="sparklr" type="authorization_code" clientId="tonr"
accessTokenUri="http://localhost:8080/sparklr/oauth/authorize"
userAuthorizationUri="http://localhost:8080/sparklr/oauth/user/authorize"/>
<!--define an oauth 2 resource for facebook. according to the facebook docs, the 'clientId' is the App ID, and the 'clientSecret' is the App Secret -->
<oauth:resource id="facebook" type="authorization_code" clientId="162646850439461" clientSecret="560ad91d992d60298ae6c7f717c8fc93"
bearerTokenMethod="query" accessTokenUri="https://graph.facebook.com/oauth/access_token"
userAuthorizationUri="https://www.facebook.com/dialog/oauth"/>
Next, just like in the previous example each controller or service bean which needs access to a protected resource is created with an internal OAuth2RestTemplate
bean. This internal bean is given a reference to the correct OAuth2ProtectedResourceDetails
bean via constructor-arg
.
接下来,就像在前面的示例中一样,每个需要访问受保护资源的控制器或服务 bean 都是使用内部OAuth2RestTemplate
bean创建的。这个内部 bean 通过 获得对正确OAuth2ProtectedResourceDetails
bean的引用constructor-arg
。
From tonr 2's spring-servlet.xml:
来自 tonr 2 的 spring-servlet.xml:
<bean id="facebookController" class="org.springframework.security.oauth.examples.tonr.mvc.FacebookController">
<!-- snipped irrelevant properties -->
<property name="facebookRestTemplate">
<bean class="org.springframework.security.oauth2.consumer.OAuth2RestTemplate">
<constructor-arg ref="facebook"/>
</bean>
</property>
<property name="tokenServices" ref="oauth2TokenServices"/>
</bean>
<bean id="sparklrService" class="org.springframework.security.oauth.examples.tonr.impl.SparklrServiceImpl">
<!-- snipped irrelevant properties -->
<property name="sparklrRestTemplate">
<bean class="org.springframework.security.oauth2.consumer.OAuth2RestTemplate">
<constructor-arg ref="sparklr"/>
</bean>
</property>
<property name="tokenServices" ref="oauth2TokenServices"/>
</bean>