java - 尝试在Spring MVC中使用OAuth保护资源

标签 java spring-mvc oauth spring-security

我们已经有在Spring MVC上用Java编写的REST Web服务,我一直在尝试保护它们。

OAuth服务器是在另一个处理访问 token 登录和创建的网站中实现的。因此,在向用户授予对Web服务的访问权限之前,我需要验证访问 token 是否正确。

但是,带有OAuth的Spring Security的文档似乎真的很差,并且示例代码实际上并未解释其作用!我什至不确定是否应该为此实现它,因为它应该是一个简单的检查。

保护这些Web服务的最佳方法是什么?最好的入门方法是什么?

感谢您的帮助。

最佳答案

重要

[2012年12月27日编辑:我在下面引用的教程现在抛出404。在github上,该教程有一个稍微更新的版本。我已经删除了看似不好的链接。由于现在缺少的教程是问问者引用的教程,因此我暂时不作介绍。 ,据我所知,此处包含的信息仍然有用,所以也许有一天我有空的时候,我将根据新教程重写它。]

该答案假定“通过OAuth服务器在另一个处理访问 token 登录和创建的网站中实现”。您的意思是您正在使用非您自己的单独站点上的服务。

背景

我当然可以与您的文档问题有关。 Spring Security可以说是任何Spring项目中最艰难的学习过程,并且OAuth支持是相当新的,并且与Spring Security分开维护。 Spring Security OAuth文档稀疏。

如果您对OAuth不太满意,请尝试获得一个! 您是在要求用户信任站点执行此标准的安全性。因此,您对本主题的理解不会有任何歧义!显而易见的起点是OAuth.net和huniverse的OAuth Beginner's Guide

如果/一旦您对OAuth的工作方式有很好的了解,我强烈建议您阅读Spring Security的“Getting Started”和“Articles and Tutorials”文档列表,以大致了解Spring Security的实现方式。

一旦您对Spring Security和OAuth有了不错的了解,那么正式的Spring Security OAuth user guide就将变得有意义。您需要特别注意要使用的OAuth版本的消费者/客户端部分(1.02.0)。

同一站点还基于上述服务tutorial的第二部分为OAuth 1.0和OAuth 2.0提供了不错的OAuth Beginner's Guide

访问 protected Restful 资源

对于您的问题,我们将重点介绍上述tutorial中Tonr照片打印服务的实现。此服务打印照片,这些照片是由外部站点托管的OAuth保护的资源。 Tonr会根据这些站点的访问控制这些资源。如有必要,这将包括重定向用户以进行用户身份验证和身份验证确认。

Spring-MVC REST服务/ Controller 本身就是外部OAuth保护的资源的使用者,通过使用请求过滤器来实现这种“延迟授权”(我的术语)行为。按照1.0 user guide:

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 1.0,使用有效的OAuthConsumerProcessingFilter过滤请求将处理获取有效访问 token 的所有事宜,并在拒绝访问时通知用户。同样,有相应的 OAuth2ClientContextFilter OAuth2ClientProcessingFilter 类。

最后,设置完毕后,您就可以使用OAuthRestTemplateOAuth2RestTemplate访问 Controller 中受OAuth保护的资源,就像您可以使用常规RestTemplate(信息here)访问不 protected 资源一样。但是,必须使用ProtectedResourceDetailsOAuth2ProtectedResourceDetails实例将它们注入(inject)到您的服务或 Controller 中。

如果听起来复杂,我有个好消息。通常,所有这些废话都是由OAuth和OAuth2 XML命名空间为您抽象和处理的

oauth命名空间在Tonr教程的XML配置文件中进行了演示,该文件位于各自的src/webapp/WEB-INF目录中。下面的示例从那里直接缩写。

如果您想了解提供方在不使用OAuth命名空间的情况下是如何工作的,建议您检查this SpringSource forum post,并遵循SECOAUTH-53问题进行更新。

OAuth 1.0示例

Tonr在这里使用Sparklr和Google的OAuth保护服务,因此它使用ProtectedResourceDetailsService标记设置了一个称为resourceDetailsoauth:resource-details-service。然后,它使用OAuthConsumerContextFilter标记设置对OAuthConsumerProcessingFilter的引用的resourceDetailsoauth:consumer。通过使用ProtectedResourceDetails标记,为每个 protected 资源提供者创建带有oauth:resource实例的过滤器。

从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>

接下来,创建sparklrServicegoogleService Bean,每个Bean都有自己的内部OAuthRestTemplate Bean,每个Bean都通过constructor-arg提供对以前创建并注入(inject)到ProtectedResourceDetails Bean中的各个ProtectedResourceDetailsService的引用。

从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示例

我的理解这里有点弱。 这样做的部分原因是OAuth2命名空间似乎抽象了很多。另外,似乎Tonr 2示例和原始Tonr示例一样没有被充实。我会尽力并在必要时进行编辑。

首先,创建一个oauth:client标签,并给它一个InMemoryOAuth2ClientTokenServices bean的引用。看来这将设置适当的过滤器。然后使用OAuth2ProtectedResourceDetails为sparklr和Facebook创建oauth:resource bean。

从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"/>

接下来,就像在前面的示例中一样,每个需要访问 protected 资源的 Controller 或服务bean都使用内部OAuth2RestTemplate bean创建。该内部bean通过OAuth2ProtectedResourceDetails给出了对正确constructor-arg bean的引用。

从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>

关于java - 尝试在Spring MVC中使用OAuth保护资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5431359/

相关文章:

java - 二维对象包装 Java

java - 获取配置文件时出现 Google Analytics API 证书异常

php - 通过 HTTP URL 查询 Gmail API

java - Spring Security OAuth(angular2 上的独立客户端)

java - RequestBody 未映射到对象

c# - Java和C#传值区别

java - 使用 Sun JConsole 访问 Websphere 7 MBean

java - 使用Maven构建hadoop应用程序时出错

java - 用于静态 html 文件和默认路径的 Spring Dispatcher servlet

java - 如何在 Spring MVC 的命令对象的列表集合中绑定(bind)一个对象