【问题标题】:Trying to protect resources with OAuth in Spring MVC尝试在 Spring MVC 中使用 OAuth 保护资源
【发布时间】:2011-07-22 19:52:19
【问题描述】:

我们已经在 Spring MVC 上用 Java 编写了 REST Web 服务,我一直在努力保护它们。

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

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

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

感谢您的帮助。

【问题讨论】:

  • 实际上,我现在有点不知所措。您是说您正在尝试使用来自另一个站点的访问令牌来保护一个站点上的资源,或者您是说您正在构建一个使用来自另一个站点的 OAuth 保护服务的站点?你是Faji,还是Beppa? hueniverse.com/2007/10/…
  • 好的,我决定按照我最初的方式解释您的问题,即在该示例中您是“Beppa”。

标签: java spring-mvc oauth spring-security


【解决方案1】:

重要

[编辑 12/27/2012:我在下面引用的教程现在抛出 404。在 github 上有本教程的略微更新版本。我已经浏览了看起来很糟糕的链接。现在我将这个原样留给后代,因为现在缺少的教程是提问者引用的教程。 据我所知,这里包含的信息仍然有用,所以也许有一天我有时间会根据新教程重写它。]

此答案假定“OAuth 服务器在另一个网站中实现,该网站处理登录和访问令牌的创建。”您的意思是您正在使用不属于您自己的单独网站上的服务。


背景

我当然可以理解您的文档问题。 Spring Security 可以说是所有 Spring 项目中学习曲线最陡峭的,并且 OAuth 支持是相当新的,并且与 Spring Security 分开维护。 Spring Security OAuth 文档稀疏的。

如果您对 OAuth 不满意,那就去买一个吧!您要求您的用户相信您的网站实施此标准的安全性。因此,您对这个主题的理解不能有任何歧义!显而易见的起点是 huniverse 的 OAuth.netOAuth 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

访问受保护的 Restful 资源

对于您的问题,我们将重点关注上述 tutorial 的 Tonr 照片打印服务的实施。此服务打印照片,这些照片是由外部站点托管的 OAuth 保护资源。 Tonr 遵从这些站点对这些资源的访问控制。这将包括在必要时重定向用户以进行用户身份验证和身份验证确认。

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

有两个请求过滤器 适用于 OAuth 消费者 逻辑。第一个过滤器, OAuthConsumerContextFilter,是 负责建立一个 OAuth 特定的安全上下文,非常 类似于 Spring Security 的 SecurityContext。安全上下文 只包含一组访问令牌 已获得的 当前用户。这个安全上下文是 在提出请求时利用 受保护的资源。

还有另一个请求过滤器, OAuthConsumerProcessingFilter,那个 可以应用于特定的 URL 或 URL 需要访问的模式 远程受保护资源。推杆 Spring Security 中的这个过滤器 过滤器链将确保任何 指定所需的访问令牌 URL模式将在之前获得 允许访问资源。

如您所见,对于 OAuth 1.0,过滤带有有效 OAuthConsumerProcessingFilter 的请求将处理获取有效访问令牌的所有事情,并在访问被拒绝时通知用户。同样有对应的OAuth2ClientContextFilterOAuth2ClientProcessingFilter 类。

最后,一旦完成所有设置,您就可以使用OAuthRestTemplateOAuth2RestTemplate 访问控制器中受OAuth 保护的资源,就像使用普通RestTemplate(信息here)访问未受保护的资源一样。但是,它们必须通过 ProtectedResourceDetailsOAuth2ProtectedResourceDetails 的实例注入到您的服务或控制器中。

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

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

如果您想了解提供方如何不使用 OAuth 命名空间的情况下工作,我建议您查看this SpringSource forum post,并关注问题SECOAUTH-53 以获取更新。

OAuth 1.0 示例

Tonr 在此处使用来自 Sparklr 和 Google 的 OAuth 保护服务,因此它使用 oauth:resource-details-service 标签设置了一个名为 resourceDetailsProtectedResourceDetailsService。然后它使用oauth:consumer 标记设置OAuthConsumerContextFilterOAuthConsumerProcessingFilter 并引用resourceDetails。这些过滤器是使用oauth:resource 标记为每个受保护的资源提供者创建的ProtectedResourceDetails 实例。


来自 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,每个都通过constructor-arg 提供对各自ProtectedResourceDetails 的引用,这些ProtectedResourceDetails 先前创建并注入@987654363 @豆。


来自 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 的引用。这似乎设置了适当的过滤器。然后使用 oauth:resource 为 sparklr 和 Facebook 创建 OAuth2ProtectedResourceDetails 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"/>


接下来,就像在前面的示例中一样,每个需要访问受保护资源的控制器或服务 bean 都是使用内部 OAuth2RestTemplate bean 创建的。通过constructor-arg 为这个内部bean 提供了对正确OAuth2ProtectedResourceDetails 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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-11
    • 2017-08-18
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    相关资源
    最近更新 更多