自定义SpringSecurity OAuth 2错误输出(未经授权)

15

我们使用Spring Security OAuth2来保护REST服务(用于服务器之间的通信,没有用户参与)。但是当用户在浏览器中尝试访问受保护的资源时,会显示:

<oauth>
    <error_description>
        An Authentication object was not found in the SecurityContext
    </error_description>
    <error>unauthorized</error>
</oauth>

我们希望这个页面能够自定义选择。有什么方法吗?

设置访问被拒绝的页面是行不通的。首先,它需要定义一个登录页面,而我们没有,因为这是纯粹的服务器之间的通信。另外,这个属性似乎已经被弃用了,自Spring 3.0以来...或者其他什么原因。

无论如何,我通过调试进入了OAuth错误处理程序。发现响应似乎会以某种方式丰富与错误页面上看到的信息。显然根本没有进行任何页面渲染,所以看起来好像没有要替换的错误页面?!

至少,如果我们不能拥有“真正”的页面,我们想隐藏使用OAuth的事实,并显示基本的“拒绝”文本。那么也许我将不得不扩展spring安全处理程序或添加自定义过滤器来修改响应?!

也许重定向到我们的错误页面?

谢谢!

编辑

有关我们当前的设置,请查看我在其他SO问题中的提问


我目前也在尝试做同样的事情。如果您有解决方案,请分享一下,我还不确定如何实现。我找到了这个(下面链接)论坛讨论,似乎与使用RestTemplate的处理程序有关... http://forum.springsource.org/showthread.php?132846-Securing-REST-with-OAuth2-Authentication-object-was-not-found-in-the-SecurityContext - rafaelxy
我现在想我明白了,OAuth服务器不会处理错误和重定向,这是尝试进行身份验证的客户端应用程序的责任。我是对的吗? - rafaelxy
我不确定这是否适用于OAuth,但这样做可以完成工作吗? security:http <security:access-denied-handler error-page="/403-error.jsp"/></security:http> - Josef Prochazka
不行,我试过了。即使我不需要它,但我还是得定义一个登录页面等等。而且它最终还是会被忽略掉。我认为它并没有生成真正的403响应。 - Pete
1个回答

15

我还必须删除oauth的详细信息,我的解决方案是实现自己的OAuth2ExceptionRenderer。

package org.some.nice.code;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.oauth2.provider.error.OAuth2ExceptionRenderer;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;

public class HeaderOnlyOAuth2ExceptionRenderer implements OAuth2ExceptionRenderer
{
    private final Log logger = LogFactory
            .getLog(MyOAuth2ExceptionRenderer.class);

    public void handleHttpEntityResponse(HttpEntity<?> responseEntity,
            ServletWebRequest webRequest) throws Exception
    {
        if (responseEntity == null)
        {
            return;
        }
        HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
        HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest);
        logger.info("filtering headers only...");
        if (responseEntity instanceof ResponseEntity
                && outputMessage instanceof ServerHttpResponse)
        {
            ((ServerHttpResponse) outputMessage)
                    .setStatusCode(((ResponseEntity<?>) responseEntity)
                            .getStatusCode());
        }
        HttpHeaders entityHeaders = responseEntity.getHeaders();
        if (!entityHeaders.isEmpty())
        {
            outputMessage.getHeaders().putAll(entityHeaders);
        }
    }

    private HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest)
            throws Exception
    {
        HttpServletRequest servletRequest = webRequest
                .getNativeRequest(HttpServletRequest.class);
        return new ServletServerHttpRequest(servletRequest);
    }

    private HttpOutputMessage createHttpOutputMessage(
            NativeWebRequest webRequest) throws Exception
    {
        HttpServletResponse servletResponse = (HttpServletResponse) webRequest
                .getNativeResponse();
        return new ServletServerHttpResponse(servletResponse);
    }
}

那么你将需要在你的Spring上下文中引用它。

     <bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="theRealm" />
<property name="exceptionRenderer" ref="headerOnlyExceptionRender" />
    </bean>

    <bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="theRealm/client" />
        <property name="typeName" value="Basic" />
<property name="exceptionRenderer" ref="headerOnlyExceptionRender" />
    </bean>



    <bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
<property name="exceptionRenderer" ref="headerOnlyExceptionRender" />
</bean>


    <bean id="headerOnlyExceptionRender" class="org.some.nice.code.HeaderOnlyOAuth2ExceptionRenderer"/>

希望它能有所帮助。


谢谢!所以就像我想的那样...会尽快尝试您的解决方案。 - Pete
只有在OAuth2客户端错误时才有效。但如果是密码错误,我就无法使其工作...我疯狂地调试Spring类,但仍然无法解决问题。 - Fernando Fradegrada

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接