以下に示す構成のSpring3アプリケーションがあります。ユーザーがページにアクセスしようとしてログインしていない場合、アクセスが拒否されました例外が発生し、スタックトレースが醜くなります。この例外を処理し、スタックトレースをダンプさせないようにするにはどうすればよいですか。独自のaccess-denied-handlerを実装しましたが、呼び出されません。
要求されたリソースのタイプに基づいて、カスタムエラーメッセージまたはページを表示したいと思います。これが私の春の構成です。
Springにaccess-denied-handlerを呼び出させるにはどうすればよいですか。これが私の春の構成です
<security:http auto-config='true'>
<security:intercept-url pattern="/static/**" filters="none"/>
<security:intercept-url pattern="/login" filters="none"/>
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page="/index"
default-target-url="/home" always-use-default-target="true"
authentication-success-handler-ref="AuthenticationSuccessHandler"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/index?error=true"/>
<security:remember-me key="myLongSecretCookieKey" token-validity-seconds="1296000"
data-source-ref="jdbcDataSource" user-service-ref="AppUserDetailsService" />
<security:access-denied-handler ref="myAccessDeniedHandler" />
</security:http>
<bean id="myAccessDeniedHandler"
class="web.exceptions.handlers.AccessDeniedExceptionHandler">
<property name="errorPage" value="/public/403.htm" />
</bean>
この例外を処理するためのカスタムクラスを以下に示します。
public class AccessDeniedExceptionHandler implements AccessDeniedHandler
{
private String errorPage;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException arg2) throws IOException, ServletException {
response.sendRedirect(errorPage);
}
public void setErrorPage(String errorPage) {
if ((errorPage != null) && !errorPage.startsWith("/")) {
throw new IllegalArgumentException("errorPage must begin with '/'");
}
this.errorPage = errorPage;
}
}
このアプリケーションを実行すると、これがエラーになります。スタックトレースとSpringDebugログの一部のみを貼り付けています。
20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.RoleVoter@5b7da0d1, returned: -1
20:39:46,173 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.AuthenticatedVoter@14c92844, returned: 0
20:39:46,178 DEBUG ExceptionTranslationFilter:154 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.Java:71)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.Java:204)
この問題を解決するにはどうすればよいですか?まず、春がその例外を投げるのを止めたいと思います。それでもスローされる場合は、フラグを立てずに処理したいと思います。
更新:web.xmlの一部も添付しました。
<!-- Hibernate filter configuration -->
<filter>
<filter-name>HibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Dispatcher Servlet -->
<servlet>
<servlet-name>rowz</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
構成では、ユーザーが入力するときに常に認証されている必要があります任意サイトのURL:
<security:intercept-url pattern="/**" access="ROLE_USER" />
ログインページに入るの場合、ユーザーが認証されていないになることを許可する必要があると思います。
<security:intercept-url pattern="/your-login-page-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/your-login-process-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/your-login-failure-url" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
次のようなURLを使用する場合:/login/start
、/login/error
、および/login/failure
次のようになります。
<security:intercept-url pattern="/login/**" access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
更新:
この構成を使用すると、フレームワークが認証されていない(匿名の)すべてのユーザーをログインページにリダイレクトし、認証されたすべてのユーザーを AccessDeniedHandler にリダイレクトする必要があります。 AccessDeniedException はフレームワークのコア部分の1つであり、それを無視することはお勧めできません。 Spring Security構成の一部のみを提供する場合、これ以上の支援は困難です。
フレームワークによってスローされる例外、デフォルトで処理される理由と方法の詳細な説明については、JavaDoc for ExceptionTranslationFilter を必ずお読みください。
可能であれば、 AuthenticationSuccessHandler 、 RememberMeAuthenticationFilter 、 AccessDeniedHandler など、追加したカスタムパーツをできるだけ多く削除して、問題が解決するかどうかを確認してください。最小限の構成を取得し、新しい機能を段階的に追加して、エラーの原因を確認してください。
あなたがあなたの質問で言及していない重要なことの1つは、このエラーメッセージの結果は何ですか? HTTP 500
を取得しますか?またはHTTP 403
?または、ログインページにリダイレクトされますか?
あなたが質問で述べたように、ユーザーが認証されておらず、ログインページにリダイレクトされた場合、それが意図された方法ではありません。 DEBUG
レベルがSpringSecurityクラスに設定されているためにのみ、 ExceptionTranslationFilter:172 によってログに記録されたエラーメッセージが表示されるようです。もしそうなら、それはそれが機能することを意図している方法でもあり、エラーをログに記録したくない場合は、SpringSecyrutyクラスのログレベルを上げるだけです。
更新2:
ログインページとプロセスを表示するページのすべてのSpringSecurityチェックをスキップするには、filters="none"
のパターンがlogin-page
で設定されたlogin-processing-url
、authentication-failure-ur
、および<security:form-login />
属性と一致する必要があります。ログイン。
<security:http auto-config='true'>
<security:intercept-url pattern="/static/**" filters="none"/>
<security:intercept-url pattern="/index" filters="none"/>
<security:intercept-url pattern="/j_spring_security_check" filters="none"/>
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page="/index"
default-target-url="/home" always-use-default-target="true"
authentication-success-handler-ref="AuthenticationSuccessHandler"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/index?error=true"/>
<security:remember-me key="myLongSecretCookieKey" token-validity-seconds="1296000"
data-source-ref="jdbcDataSource" user-service-ref="AppUserDetailsService" />
<security:access-denied-handler ref="myAccessDeniedHandler" />
</security:http>
AccessDeniedHandler
は、ユーザーがログインし、リソースへのアクセス許可がない場合( ソースはこちら )に呼び出されます。ユーザーがログインしていないときにログインページの要求を処理する場合、security-context:
<http ... entry-point-ref="customAuthenticationEntryPoint">
そして、customAuthenticationEntryPointを定義します。
<beans:bean id="customAuthenticationEntryPoint" class="pl.wsiadamy.webapp.controller.util.CustomAuthenticationEntryPoint">
</beans:bean>
[〜#〜] tip [〜#〜]、ExceptionTranslationFilter
。効果なしでorg.springframework.security.web.access.ExceptionTranslationFilter
をオーバーライドしようとしました:
<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="customAuthenticationEntryPoint"/>
<beans:property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</beans:bean>
<beans:bean id="accessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/accessDenied.htm"/>
</beans:bean>
ref="customAuthenticationEntryPoint"
は呼び出されませんでした。
次の方法でSpringAccess拒否ページを追加しました:Spring Frame Work:3.1 Spring Security:3.1、Java 1.5+
* -security.xmlのエントリ:
<security:access-denied-handler error-page="/<My Any error page controller name>" />
例:
<security:access-denied-handler error-page="/accessDeniedPage.htm" />
エラーページは常に「/」で始まります
コントローラのエントリ:
@Controller
public class RedirectAccessDenied {
@RequestMapping(value = "/accessDeniedPage.htm", method = RequestMethod.GET)
public String redirectAccessDenied(Model model) throws IOException, ServletException {
System.out.println("############### Redirect Access Denied Handler!");
return "403";
}
}
ここで403は私のJSP名です。
Spring Securityは、AuthenticationEntryPointオブジェクトを使用して、ユーザーが認証を必要とするときに何をするかを決定します。独自のAuthenticationEntryPointBean( javadocを参照 )を作成してから、http要素にentryPoint属性を設定できます。
<http entry-point-ref="entryPointBean" .... />
ただし、デフォルトでは、form-login要素はLoginUrlAuthenticationEntryPointを作成し、認証されていないすべてのユーザーをログインページにリダイレクトするため、これを自分で行う必要はありません。実際、投稿したログには、ユーザーを認証エントリポイントに転送していると記載されています:「アクセスが拒否されました(ユーザーは匿名です)。認証エントリポイントにリダイレクトしています」。
ログインURLのフィルターチェーンをオフにしたことが問題なのだろうか。フィルタをnoneに設定する(つまり、スプリングセキュリティが完全にバイパスされる)代わりに、フィルタをオンのままにして、次のように無制限のアクセスを許可してみてください。
<security:intercept-url pattern="/login" access="permitAll" />
それでも問題が解決しない場合は、ログの残りの部分を投稿して、リクエストがエントリポイントに転送された後に何が起こるかを確認してください。
プログラムによる解決策:
@Order(1)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//
// ...
//
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
super.handle(request, response, accessDeniedException);
accessDeniedException.printStackTrace();
}
});
//
// ...
//
}
}
Web.xmlが転送要求をサポートしていることを確認できますか?
errorPageはFORWARDリクエストであり、ほとんどの場合web.xmlではREDIRECTSのみをサポートしています。考えてみれば、あなたのコードは私には問題ないように見えます。
編集済み
別の観点とこれは、作業コードからのみ取得されます。ご覧ください 認証済み投票者クラス
注釈を無効にする
<global-method-security pre-post-annotations="disabled"
secured-annotations="disabled" access-decision-manager-ref="accessDecisionManager">
</global-method-security>
フィルタをバイパスする
<http auto-config="true" use-expressions="true"
access-decision-manager-ref="accessDecisionManager"
access-denied-page="/accessDenied">
<intercept-url pattern="/appsecurity/login.jsp" filters="none" />
<intercept-url pattern="/changePassword" filters="none" />
<intercept-url pattern="/pageNotFound" filters="none" />
<intercept-url pattern="/accessDenied" filters="none" />
<intercept-url pattern="/forgotPassword" filters="none" />
<intercept-url pattern="/**" filters="none" />
<form-login login-processing-url="/j_spring_security_check"
default-target-url="/home" login-page="/loginDetails"
authentication-failure-handler-ref="authenticationExceptionHandler"
authentication-failure-url="/?login_error=t" />
<logout logout-url="/j_spring_security_logout"
invalidate-session="true" logout-success-url="/" />
<remember-me />
<!-- Uncomment to limit the number of sessions a user can have -->
<session-management invalid-session-url="/">
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" />
</session-management>
</http>
カスタム決定投票者
<bean id="customVoter" class="xyz.appsecurity.helper.CustomDecisionVoter" />
意思決定マネージャーにアクセスする
<!-- Define AccessDesisionManager as UnanimousBased -->
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<property name="decisionVoters">
<list>
<ref bean="customVoter" />
<!-- <bean class="org.springframework.security.access.vote.RoleVoter"
/> -->
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</property>
</bean>
認証例外ハンドラ
<bean id="authenticationExceptionHandler"
class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<property name="exceptionMappings">
<props>
<!-- /error.jsp -->
<prop
key="org.springframework.security.authentication.BadCredentialsException">/?login_error=t</prop>
<!-- /getnewpassword.jsp -->
<prop
key="org.springframework.security.authentication.CredentialsExpiredException">/changePassword</prop>
<!-- /lockedoutpage.jsp -->
<prop key="org.springframework.security.authentication.LockedException">/?login_error=t</prop>
<!-- /unauthorizeduser.jsp -->
<prop
key="org.springframework.security.authentication.DisabledException">/?login_error=t</prop>
</props>
</property>
</bean>
Springは、ログインページ(「/ index」)にログインしていないユーザーをリダイレクトしようとしているようですが、それ自体は保護されたURLです。
もう1つの可能性は、/ public/403.htmlを表示しようとしますが、これもセキュリティ構成によって保護されています。
次のエントリを追加して試すことができますか?
<security:intercept-url pattern="/login" filters="none" />
<security:intercept-url pattern="/public/**" filters="none" />