SpringがJSFで使用されている(PrimeFacesを使用している)プロジェクトがあります。これまではSpring Securityにxml設定を使用していましたが、私はJavaベースの設定に移植することが任されています。Spring Securityのログイン処理のURLがありません
私は今applicationContext.xml
にXML設定から行ってきた:
<!-- Security Config -->
<security:http security="none" pattern="/javax.faces.resource/**"/>
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/login.xhtml" access="permitAll"/>
<security:intercept-url pattern="/**" access="permitAll"/>
<security:form-login login-page="/login.xhtml"
login-processing-url="/do_login"
authentication-failure-url="/login.xhtml"
authentication-success-handler-ref="authSuccessHandler"
username-parameter="email"
password-parameter="password"/>
<security:logout logout-success-url="/login.xhtml"
logout-url="/do_logout"
delete-cookies="JSESSIONID"/>
</security:http>
<bean id="userDetails" class="com.madmob.madmoney.security.UserDetailsServiceImpl"></bean>
<bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<constructor-arg name="strength" value="10" />
</bean>
<bean id="authSuccessHandler" class="com.madmob.madmoney.security.UserAuthenticationSuccessHandler"></bean>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetails">
<security:password-encoder ref="encoder" />
</security:authentication-provider>
</security:authentication-manager>
とweb.xml
から次
<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>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
次のJavaベースの構成に:
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserAuthenticationSuccessHandler authSuccessHandler;
@Autowired
DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.jdbcAuthentication().usersByUsernameQuery("SELECT email, passowrd, enabled FROM app_user WHERE email = ?")
.authoritiesByUsernameQuery("SELECT role_name FROM role WHERE role_id = (SELECT role_id FROM user_role WHERE email = ?)")
.dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder(10));
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/javax.faces.resource/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin().loginPage("/login.xhtml").loginProcessingUrl("/do_login")
.failureUrl("/login.xhtml").successHandler(authSuccessHandler)
.usernameParameter("email").passwordParameter("password").permitAll()
.and()
.logout().logoutSuccessUrl("/login.xhtml").logoutUrl("/do_logout")
.deleteCookies("JSESSIONID");
// temp user add form
// TODO remove
http.antMatcher("/userForm.xhtml").authorizeRequests().anyRequest().permitAll();
}
}
と
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
protected EnumSet<DispatcherType> getSecurityDispatcherTypes() {
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC, DispatcherType.FORWARD);
}
}
ログインは、XMLベースの設定でうまくいきましたが、私はとTomcatが404を返すログインしようとした場合の切り替え以降:The requested resource is not available.
すべてのページに関係なく、ログインまたはいないのにもアクセス可能です。
以下は私のログインフォームです:
<h:form id="loginForm" prependId="false" styleClass="panel-body">
<div>
<p:inputText id="email" required="true" label="email"
value="#{loginBean.email}" styleClass="form-control f-75"
placeholder="Email Address"></p:inputText>
<h:message for="email" styleClass="validationMsg"/>
</div>
<div class="spacer"/>
<div>
<p:password id="password" required="true" label="password"
value="#{loginBean.password}" placeholder="Password"></p:password>
<h:message for="password" styleClass="validationMsg"/>
<h:messages globalOnly="true" styleClass="validationMsg" />
</div>
<div class="spacer"/>
<p:commandButton id="login" value="Log in"
actionListener="#{loginBean.login}" ajax="false"/>
</h:form>
と私のバッキングBeanでのログイン方法:
/**
* Forwards login parameters to Spring Security
*/
public void login(ActionEvent loginEvt){
// setup external context
logger.info("Starting login");
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
// setup dispatcher for spring security
logger.info("Setup dispatcher");
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/do_login");
try {
// forward request
logger.info("Forwarding request to spring security");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
} catch (ServletException sEx) {
logger.error("The servlet has encountered a problem", sEx);
} catch (IOException ioEx) {
logger.error("An I/O error has occured", ioEx);
} catch (Exception ex) {
logger.error("An error has occured", ex);
}
// finish response
FacesContext.getCurrentInstance().responseComplete();
}
これは、Java 1.8、Tomcatの7、春と春のセキュリティ3.2.5上で実行されています、JSF 2.1、Primefaces 5
問題が発生してから試したこと:
- 最初に
SecurityConfig
のみを使用していたので、が追加されました。 - 処理URLと転送先を指定しないで、デフォルトのSpring Security url(
j_spring_security_check
)を使用して試行します。私は問題を発見し解決
設定なしでSpring Securityをブートストラップします。 'AbstractSecurityWebApplicationInitializer(Class > ...)を呼び出す必要があります。デフォルトのno-argsコンストラクタの代わりに 'configurationClasses)'コンストラクタを使用します。あるいは、 'ContextLoaderListener'をロードする別の手段がある場合は、それに設定クラスを追加してください。 –
'ContextLoaderListener'は私の' web.xml'で定義されています。そのコンストラクタを呼び出すと、既にルートアプリケーションコンテキストが存在するため例外が発生します。 '@ EnableWebSecurity'アノテーションがこれを処理すべきであること、あるいは何か不足していることを知っている限り、注意してください。 (パッケージはコンポーネントスキャンの一部ですが、手動でBeanをxmlに手動で定義するときも同じ問題が発生しました) – Vinc
設定がロードされていない場合は、何も効果を持たないアノテーションを必要な数だけ配置できます。だからコンフィグレーションがロードされていることを確認してください(他のものがロードされているにも関わらず、 'springSecurityFilterChain'という名前のBeanが定義されていないことを示すメッセージでアプリケーションの起動に失敗します)。 –