在自定义的UserDetailsS​​ervice loadUserByUsername参数的用户名始终是空的 [英] Parameter username of loadUserByUsername in custom UserDetailsService is always empty

查看:3628
本文介绍了在自定义的UserDetailsS​​ervice loadUserByUsername参数的用户名始终是空的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个基于表单的登录使用弹簧安全使用自定义的UserDetailsS​​ervice的工作。登录表单似乎是正确的提交。在调试应用程序,我发现原来提交的请求到达UsernamePasswordAut​​henticationFilter的attemptAuthentication方法。但它看起来像,因为他们仍然空请求参数不能映射到用户名和密码字段。也因此我的自定义的UserDetailsS​​ervice的loadByUsername方法的参数名保留为空,我不能够成功登录。

I am working on a form based login using spring-security with a customized UserDetailsService. The login form seems to be submitted correctly. While debugging the application I found out that the submitted request arrived at the attemptAuthentication method of the UsernamePasswordAuthenticationFilter. But it looks like the the request parameter cannot be mapped to the username and password field because they remain empty. Therefore also the parameter username of the loadByUsername method of my custom UserDetailsService remains empty and I am not able to successfully login.

我已经尝试了很多,但现在我不知道这个问题可能是什么。我也很新的春天安全,但我想我不是太遥远了。

I have tried a lot, but for now I have no clue what the problem could be. I am also quite new to spring-security, but I suppose I am not too far away.

我总结了code尽可能多地。如果您需要了解更多信息,请让我现在。

I summarized the code as much as possible. If you need more information please let me now.

首先,我成立了springSecurityFilterChain在web.xml中:

First I set up the springSecurityFilterChain in web.xml:

<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>

这是我的applicationContext.xml与参考customUserDetailsS​​ervice:

That is my applicationContext.xml with the reference to customUserDetailsService:

<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文件以合适的身份验证提供者:

The applicationContext-security.xml with the appropriate authentication-provider:

<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中我添加了一个LoginErrorPhaseListener检测BadCredentialsException,并且增加了LoginBean:

In faces-config.xml I have added a LoginErrorPhaseListener to detect BadCredentialsException and added the 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 IS拥有用户名的密码字段被提交到loginBean:

index.xhtml is has username an password field an is submitted to the 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

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)。因此当然没有有效的用户发现:

Now in CustomUserDetailsService.java the correct user should be loaded, but here the method parameter username is always empty (not null). And therefore of course no valid user is found:

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);
}

}

希望你能帮助我在这一个。

Hope you can help me on this one.

推荐答案

如果您通过这种方式,你需要设置集成Spring Security的使用JSF prependId =FALSE在您的形式,否则春季安全要求的字段名称将与表单ID ppended $ p $:

If you integrate Spring Security with JSF this way you need to set prependId = "false" in your form, otherwise field names required by Spring Security will be prepended with form id:

<h:form id="loginForm" prependId = "false">...</h:form>

这篇关于在自定义的UserDetailsS​​ervice loadUserByUsername参数的用户名始终是空的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆