Spring MVC + Spring Security+Hibernateを使用してRESTfulAPIを作成しています。APIは、JSONとHTMLの両方を生成できます。スプリングセキュリティのために適切なエラー処理を行うことは、私に頭痛の種を与えています。
認証はさまざまな方法で行うことができます。BasicAuth、POSTリクエストのさまざまなパラメータ、およびWebログインを介して。認証メカニズムごと<http>
に、spring securityxmlconfigのnamespace要素で宣言されたフィルターがあります。
すべての春の例外をカスタムで処理しますHandlerExceptionResolver
。これは、コントローラーでスローされたすべての例外に対して正常に機能しますが、カスタムスプリングセキュリティフィルターでスローされたカスタム例外を処理する方法がわかりません。スプリングセキュリティフィルターはコントローラーが呼び出される前に来るので、カスタムスプリングセキュリティフィルターでスローする例外は表示されません。
私はここにstackoverflowでこの質問を見つけました:SpringSecurity
でカスタム例外を使用してください。ただし、そこでスローされる例外をどこで処理するのかわかりません。このアプローチを試しましたが、カスタムHandlerExceptionResolver
は呼び出されません。代わりに、tomcatによってレンダリングされた醜いスタックトレースがユーザーに表示されます。
なぜ私たちはこれが必要なのですか?
ユーザーはアクティブ化および非アクティブ化できます。それらが非アクティブ化され、特定のアクションを実行しようとした場合、カスタムエラーメッセージとともにJSONを返します。これは、スプリングセキュリティが。をスローしたときに表示されるものとは異なる必要がありますAccessDeniedException
。AccessDeniedException
どういうわけか私たちHandlerExceptionResolver
にそれをします、しかし私はどれほど正確に続くことができませんでした。
考えられる解決策ExceptionTranslationFilter
カスタム例外をスローするときにこれは呼び出されません(doFilter()メソッドのcatchステートメントにブレークポイントを設定します)。私の理解では、このcatchブロックを呼び出し、認証エントリポイントを使用する必要があります。
別の可能性:ExceptionTranslationFilter
スプリングセキュリティフィルターチェーンと同様のことを行い、それが行うことと同様のことを行うことができますAccessDeniedHandler
。
RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
dispatcher.forward(request, response);
リクエストにいくつかのパラメーター(エラーコード、理由など)を追加し、JSONまたはHTMLでのレンダリングを処理するコントローラーを指すようにすることができます。
これが私たちの構成の短い抜粋です:
春のセキュリティ:
<http create-session="stateless" use-expressions="true" >
<!-- Try getting the authorization object from the request parameters. -->
<security:custom-filter ref="filter1" after="SECURITY_CONTEXT_FILTER"/>
<security:custom-filter ref="filter2" before="LOGOUT_FILTER"/>
<!-- Intercept certain URLS differently -->
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<!-- Some more stuff here -->
<intercept-url pattern="/**" access="denyAll" />
<http-basic />
</http>
HandlerExceptionResolverのAppConfig
@Bean
public HandlerExceptionResolver handlerExceptionResolver(){
logger.info("creating handler exception resolver");
return new AllExceptionHandler();
}
カスタムHandlerExceptionResolver
public class AllExceptionHandler implements HandlerExceptionResolver {
private static final Logger logger = LoggerFactory
.getLogger(AppConfig.class);
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
// This is just a snipped of the real method code
return new ModelAndView("errorPage");
}
フィルタの1つの関連部分:
try {
Authentication authResult = authenticationManger.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authResult);
}
catch(AuthenticationException failed) {
SecurityContextHolder.clearContext();
throw failed;
}
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>xxx.xxx.xxx.config</param-value>
</context-param>
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>LIVE</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- Add multipart support for files up to 10 MB -->
<multipart-config>
<max-file-size>10000000</max-file-size>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<!-- Map filters -->
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<error-code>404</error-code>
<location>/handle/404</location>
</error-page>
</web-app>
誰かがこれをどのように解決できるかについての指針を持っていますか?私はグーグルで多くの記事を調べました、それらのほとんどはフィルターがリクエストを認証することができないときに春のセキュリティによってスローされたAccessDeniedExceptionを処理する方法を説明しています。
SpringSecurity3.1.0とSpringWebMVC3.1.0を使用しています。