问题描述
我在一个基于表单的登录使用弹簧安全使用自定义的UserDetailsService的工作。登录表单似乎是正确的提交。在调试应用程序,我发现原来提交的请求到达UsernamePasswordAuthenticationFilter的attemptAuthentication方法。但它看起来像,因为他们仍然空请求参数不能映射到用户名和密码字段。也因此我的自定义的UserDetailsService的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与参考customUserDetailsService:
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;
}
}
现在在CustomUserDetailsService.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>
这篇关于在自定义的UserDetailsService loadUserByUsername参数的用户名始终是空的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!