0

カスタマイズされた UserDetailsS​​ervice で spring-security を使用して、フォームベースのログインに取り組んでいます。ログインフォームは正しく送信されているようです。アプリケーションをデバッグしているときに、送信されたリクエストが UsernamePasswordAuthenticationFilter の試行認証メソッドに到着したことがわかりました。しかし、空のままであるため、要求パラメーターをユーザー名とパスワードのフィールドにマップできないようです。したがって、カスタム UserDetailsS​​ervice の loadByUsername メソッドのパラメータ username も空のままで、正常にログインできません。

私は多くのことを試しましたが、今のところ、何が問題なのかわかりません。私は春のセキュリティにもまったく慣れていませんが、それほど遠くないと思います。

コードを可能な限りまとめました。さらに情報が必要な場合は、今すぐお知らせください。

まず、web.xml で springSecurityFilterChain をセットアップします。

<welcome-file-list>
    <welcome-file>index.xhtml</welcome-file>
</welcome-file-list>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:WEB-INF/applicationContext.xml,
        classpath:WEB-INF/applicationContext-security.xml
    </param-value>
</context-param>

<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>classpath:log4j.properties</param-value>
</context-param>

<!-- Filter Config -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<!-- Filter Mappings -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

<!-- Spring Configuration -->
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
</listener>

これは、customUserDetailsS​​ervice への参照を含む私の applicationContext.xml です。

<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    ...
</bean>

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    ...
</bean>

<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    ...
</bean>

<!-- Authentification -->
<bean id="customUserDetailsService" class="com.seraphim.security.auth.CustomUserDetailsService"/>

<!-- Transaction -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>

<context:component-scan base-package="com.seraphim"/>

<context:annotation-config/>

<tx:annotation-driven transaction-manager="transactionManager"/>

適切な認証プロバイダーを含む applicationContext-security.xml:

<http
    auto-config="true"
    access-denied-page="/accessDenied.jsp">

    <intercept-url
            pattern="/pages/**"
            access="ROLE_ADMIN,ROLE_USER"/>
    <intercept-url
            pattern="/**"
            access="IS_AUTHENTICATED_ANONYMOUSLY"/>

    <form-login
            login-processing-url="/j_spring_security_check"
            login-page="/index.xhtml"
            default-target-url="/pages/main.xhtml"
            authentication-failure-url="/index.xhtml"/>

    <logout
            logout-url="/logout*"
            logout-success-url="/"/>

</http>

<authentication-manager>
    <authentication-provider user-service-ref="customUserDetailsService">
        <password-encoder hash="md5"/>
    </authentication-provider>
</authentication-manager>

faces-config.xml に、BadCredentialsException を検出する LoginErrorPhaseListener を追加し、LoginBean を追加しました。

<lifecycle>
    <phase-listener>com.seraphim.security.auth.LoginErrorPhaseListener</phase-listener>
</lifecycle>

<managed-bean>
    <managed-bean-name>loginBean</managed-bean-name>
    <managed-bean-class>
        com.seraphim.bean.LoginBean
    </managed-bean-class>
    <managed-bean-scope>
        request
    </managed-bean-scope>
</managed-bean>

index.xhtml にはユーザー名とパスワード フィールドがあり、loginBean に送信されます。

<h:form id="loginForm">

    <h:outputLabel for="j_username" value="User:"/>
    <p:inputText id='j_username' label="user" required="true"/>

    <h:outputLabel for="j_password" value="Password:"/>

    <h:inputSecret id='j_password' label="pass2" required="true"/>

    <h:outputLabel for="_spring_security_remember_me" value="Remember "/>
    <p:selectBooleanCheckbox id='_spring_security_remember_me'/>

    <h:outputLabel/>
    <h:commandButton type="submit" id="login" action="#{loginBean.doLogin}" value="Login"/>

</h:form>

LoginBean.java

@Component
@Scope("request")
public class LoginBean {

  public String doLogin() throws IOException, ServletException {

    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

    RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
            .getRequestDispatcher("/j_spring_security_check");

    dispatcher.forward((ServletRequest) context.getRequest(), (ServletResponse) context.getResponse());

    FacesContext.getCurrentInstance().responseComplete();

    // It's OK to return null here because Faces is just going to exit.
    return null;

  }
}

CustomUserDetailsS​​ervice.java で正しいユーザーをロードする必要がありますが、ここではメソッド パラメーターのユーザー名は常に空です (null ではありません)。したがって、もちろん有効なユーザーは見つかりません。

public class CustomUserDetailsService implements UserDetailsService {

@Resource
IUserDao userDao;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    User user = userDao.findByUsername(username);

    if (user == null) {
        throw new UsernameNotFoundException("user not found");
    }

    // build roles for user
    Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
    if(user.isAdmin()) {
        authorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
    }

    return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(),
            user.isEnabled(), 
            user.isAccountNonExpired(),
            user.isCredentialsNonExpired(), 
            user.isAccountNonLocked(),
            authorities);
}

}

これで私を助けてくれることを願っています。

4

1 に答える 1

1

このように Spring Security を JSF と統合する場合prependId = "false"は、フォームに設定する必要があります。そうしないと、Spring Security で必要なフィールド名の先頭にフォーム ID が追加されます。

<h:form id="loginForm" prependId = "false">...</h:form>
于 2012-07-09T07:44:26.480 に答える