自定义SpringSecurity OAuth 2错误输出(未经授权) [英] Customize SpringSecurity OAuth 2 Error Output (unauthorized)
问题描述
我们使用Spring Security OAuth2保护我们的REST服务(用于服务器到服务器的通信,无需用户参与)。但是,当一个人试图在浏览器中访问受保护资源时,它将显示:
We secure our REST services (for server to server communication, no user involved) with Spring Security OAuth2. However when one tries to access a protected resource in a browser, it will show:
<oauth>
<error_description>
An Authentication object was not found in the SecurityContext
</error_description>
<error>unauthorized</error>
</oauth>
我们希望这是我们自己选择的自定义页面。有办法吗?
We want this to be a custom page of our own choosing. Is there a way?
设置访问被拒绝页面是行不通的。首先,它需要定义我们没有的登录页面,因为这是一个纯粹的服务器到服务器通信。对于另一个,这个属性应该是从Spring 3.0以后弃用的。或者其他什么。
Setting the access-denied-page won't do. For one it requires the definition of a login page which we don't have as this is a pure server to server communication. For another this attribute is supposedly deprecated since Spring 3.0.. or something.
无论如何..调试我的方式进入OAuth错误处理。并且发现响应似乎以某种方式通过我在错误页面上看到的信息得到了丰富。显然没有完成任何页面渲染,所以看起来没有要替换的错误页面..?!
Anyway.. Debugged my way into the OAuth Error Handling. And found that the response seems to somehow get enriched with the information I see on the error page. Apparently no page rendering at all is done so it looks like there is no error page to replace..?!
至少我们想要隐藏我们使用OAuth这一事实如果我们不能有一个真正的页面,只显示一个基本的拒绝文本。所以也许我必须扩展spring安全处理程序或添加自定义过滤器来修改响应?!
At least we want to hide the fact that we use OAuth and just display a basic "Denied" text if we can't have a "real" page.. So maybe I'll have to extend the spring security handler or add a custom filter to modify the response?!
也许重定向到我们的错误页面?
Maybe a redirect to our error page?
谢谢!
修改
对于我们当前的设置,请检查我的另一个问题在这里
For our current setup check my other SO question here
推荐答案
<我必须删除oauth细节,我的解决方案是实现我自己的OAuth2ExceptionRenderer
I had to remove the oauth detail too and my solution was to implement my own 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);
}
}
然后你必须在你的春天环境中引用它
Then you will have to reference it within your spring context
<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"/>
希望有所帮助。
这篇关于自定义SpringSecurity OAuth 2错误输出(未经授权)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!