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

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

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

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

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

感谢您的帮助。

java大神给出的解决方案

重要

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

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

背景

我当然可以与您的文档问题有关。 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.0或2.0)的“客户/客户端”部分。

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

访问受保护的宁静资源

对于您的问题,我们将重点介绍上述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)访问不受保护的资源一样。但是,必须使用ProtectedResourceDetails或OAuth2ProtectedResourceDetails实例将它们注入到您的服务或控制器中。

如果这听起来很复杂,我有个好消息。通常,所有这些废话都是由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标记,为每个受保护资源提供程序的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,每个都有它们自己的内部OAuthRestTemplate bean,每个bean通过constructor-arg提供对以前创建并注入到<cc中的各个ProtectedResourceDetails的引用。 >豆。

从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示例一样没有被充实。我会尽力并在必要时进行编辑。

首先,创建一个ProtectedResourceDetailsService标记,并提供对oauth:client bean的引用。看来这将设置适当的过滤器。然后,使用InMemoryOAuth2ClientTokenServices为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都使用内部oauth:resource Bean创建。通过OAuth2RestTemplate将此内部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>

页面加载而不是提交时发生struts验证 - java

请原谅我;我对Struts有点陌生。我遇到一个问题,即页面加载而不是我实际提交表单时发生了验证。我整天都在论坛上搜寻和搜寻,没有任何运气。我显然做错了一些事情,应该很容易确定,但是我还没有发现问题所在。这是我的struts.xml的片段:<action name="*Test" method="{1}" clas…

DataSourceTransactionManager和JndiObjectFactoryBean和JdbcTemplate的用途是什么? - java

以下的用途是什么:org.springframework.jdbc.core.JdbcTemplate org.springframework.jdbc.datasource.DataSourceTransactionManager org.springframework.jndi.JndiObjectFactoryBean <tx:annotatio…

AppCompat不支持当前主题 - java

我的应用在Android N上运行正常,但在Android M上的setContentView(R.layout.activity_main)崩溃: Caused by: java.lang.IllegalArgumentException: AppCompat does not support the current theme features: { w…

当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…

java.net.URI.create异常 - java

java.net.URI.create("http://adserver.adtech.de/adlink|3.0") 抛出java.net.URISyntaxException: Illegal character in path at index 32: http://adserver.adtech.de/adlink|3.0 虽然n…