如何强制 Spring Security OAuth 2 使用 JSON 而不是 XML?
How to force Spring Security OAuth 2 to use JSON instead of XML?
我已经创建了 Spring MVC 应用程序并设置了 Spring Security OAuth 2。
从我的浏览器调用方法时,我得到 XML:
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
浏览器发送以下 header:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
当我设置 json 接受 header 我得到 JSON。我需要强制我的授权服务器始终发送 JSON。还没有找到任何解决方案。谢谢。
对于 Spring 安全 OAuth 异常是使用 DefaultOAuth2ExceptionRenderer 呈现的
它将根据提供的 MessageConverters 匹配接收到的 Accept HTTP header。在你的情况下,Spring Boot 似乎自动分配了 XML 和 JSON MessageConverters。此行为已确认,基于接受 header 您正在接收以适当 Content-Type
呈现的异常
没有 Accept header DefaultOAuth2ExceptionRenderer 默认为 Accept: * 并且通常响应的第一个 MessageConverter 是 XML一个.
如果 XML 在您的应用程序中不受欢迎,您需要了解为什么它得到支持(很可能您的类路径中有 FasterXML Jackson)。
如果您想同时支持两者,但又想拥有 JSON 默认值,这将要求您编写自己的 OAuth2ExceptionRendrer 实现,并确保在中呈现异常JSON。更好的方法是将您的 impl 挂接到 ContentNegotationManager 并将 MediaType 解析委托给它。
有关 ContentNegotationManager 的更多信息,请查看此 link:
https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
设置Accept: application/json
为header属性
强制OAuth2很简单,你自己先想办法就可以了:
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private AccessDeniedHandler accessDeniedHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.access("#oauth2.hasScope('read')")
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
}
然后您需要创建 authenticationEntryPoint 和 accessDeniedHandler @Bean
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedHandler () {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
response.getWriter().append("\"FORBIDDEN\"");
response.setStatus(HttpStatus.FORBIDDEN.value());
}
};
}
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.getWriter().append("\"UNAUTHORIZED\"");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
}
};
}
随意转换成JSON你喜欢的方式,我会推荐你jackson。
要扩展 BigDong 的答案,您不需要创建自己的入口点和异常处理程序 类 您只需要替换渲染器并设置您要使用的消息转换器的类型。例如,在我的 Oauth2Config 中,我执行以下操作:
httpSecurity.authorizeRequests()
.requestMatchers(getAuthorizedRequestMatcher())
.authenticated()
...
.and()
.exceptionHandling().accessDeniedHandler(buildAccessDeniedHandler(configureExceptionRenderer()))
.and()
.exceptionHandling().authenticationEntryPoint(buildAuthenticationEntryPoint(configureExceptionRenderer()));
渲染是用我想要的消息转换器创建的:
protected OAuth2ExceptionRenderer configureExceptionRenderer() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter(Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build()));
messageConverters.add(new ByteArrayHttpMessageConverter());
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);
messageConverters.add(stringConverter);
... add more if you want ...
DefaultOAuth2ExceptionRenderer renderer = new DefaultOAuth2ExceptionRenderer();
renderer.setMessageConverters(messageConverters);
return renderer;
}
最后实例化入口点和错误处理程序并设置渲染器:
protected AuthenticationEntryPoint buildAuthenticationEntryPoint(OAuth2ExceptionRenderer renderer) {
OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setExceptionRenderer(renderer);
return entryPoint;
}
protected AccessDeniedHandler buildAccessDeniedHandler(OAuth2ExceptionRenderer renderer) {
OAuth2AccessDeniedHandler handler = new OAuth2AccessDeniedHandler();
handler.setExceptionRenderer(renderer);
return handler;
}
我已经创建了 Spring MVC 应用程序并设置了 Spring Security OAuth 2。 从我的浏览器调用方法时,我得到 XML:
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
浏览器发送以下 header:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
当我设置 json 接受 header 我得到 JSON。我需要强制我的授权服务器始终发送 JSON。还没有找到任何解决方案。谢谢。
对于 Spring 安全 OAuth 异常是使用 DefaultOAuth2ExceptionRenderer 呈现的
它将根据提供的 MessageConverters 匹配接收到的 Accept HTTP header。在你的情况下,Spring Boot 似乎自动分配了 XML 和 JSON MessageConverters。此行为已确认,基于接受 header 您正在接收以适当 Content-Type
呈现的异常没有 Accept header DefaultOAuth2ExceptionRenderer 默认为 Accept: * 并且通常响应的第一个 MessageConverter 是 XML一个.
如果 XML 在您的应用程序中不受欢迎,您需要了解为什么它得到支持(很可能您的类路径中有 FasterXML Jackson)。
如果您想同时支持两者,但又想拥有 JSON 默认值,这将要求您编写自己的 OAuth2ExceptionRendrer 实现,并确保在中呈现异常JSON。更好的方法是将您的 impl 挂接到 ContentNegotationManager 并将 MediaType 解析委托给它。
有关 ContentNegotationManager 的更多信息,请查看此 link:
https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
设置Accept: application/json
为header属性
强制OAuth2很简单,你自己先想办法就可以了:
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private AccessDeniedHandler accessDeniedHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.access("#oauth2.hasScope('read')")
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
}
然后您需要创建 authenticationEntryPoint 和 accessDeniedHandler @Bean
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedHandler () {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
response.getWriter().append("\"FORBIDDEN\"");
response.setStatus(HttpStatus.FORBIDDEN.value());
}
};
}
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.getWriter().append("\"UNAUTHORIZED\"");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
}
};
}
随意转换成JSON你喜欢的方式,我会推荐你jackson。
要扩展 BigDong 的答案,您不需要创建自己的入口点和异常处理程序 类 您只需要替换渲染器并设置您要使用的消息转换器的类型。例如,在我的 Oauth2Config 中,我执行以下操作:
httpSecurity.authorizeRequests()
.requestMatchers(getAuthorizedRequestMatcher())
.authenticated()
...
.and()
.exceptionHandling().accessDeniedHandler(buildAccessDeniedHandler(configureExceptionRenderer()))
.and()
.exceptionHandling().authenticationEntryPoint(buildAuthenticationEntryPoint(configureExceptionRenderer()));
渲染是用我想要的消息转换器创建的:
protected OAuth2ExceptionRenderer configureExceptionRenderer() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter(Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build()));
messageConverters.add(new ByteArrayHttpMessageConverter());
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);
messageConverters.add(stringConverter);
... add more if you want ...
DefaultOAuth2ExceptionRenderer renderer = new DefaultOAuth2ExceptionRenderer();
renderer.setMessageConverters(messageConverters);
return renderer;
}
最后实例化入口点和错误处理程序并设置渲染器:
protected AuthenticationEntryPoint buildAuthenticationEntryPoint(OAuth2ExceptionRenderer renderer) {
OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setExceptionRenderer(renderer);
return entryPoint;
}
protected AccessDeniedHandler buildAccessDeniedHandler(OAuth2ExceptionRenderer renderer) {
OAuth2AccessDeniedHandler handler = new OAuth2AccessDeniedHandler();
handler.setExceptionRenderer(renderer);
return handler;
}