在 Spring Security 中使用 UserDetailSservice 使用电子邮件进行登录身份验证

Posted

技术标签:

【中文标题】在 Spring Security 中使用 UserDetailSservice 使用电子邮件进行登录身份验证【英文标题】:Login Authentication with Email using UserDetailService in SpringSecurity 【发布时间】:2017-07-05 07:26:53 【问题描述】:

我正在尝试使用 Spring Security UserDetailService 身份验证使用电子邮件而不是用户名登录,但我无法登录并获取

org.springframework.security.authentication.InternalAuthenticationServiceException.

当我调试代码时,调试器不跟踪

用户 user = userDao.findByUserName(useremail);来自 UserServiceImpl.java 并发生错误。

可能有一个步骤需要更多的地方。 配置和Java代码和错误日志如下:-

ApplicationContext.xml

<security:http auto-config="true">
        <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
        <security:intercept-url pattern="/customer/**" access="ROLE_USER" />
        <security:form-login login-page="/login"
            default-target-url="/product/productList/all" authentication-failure-url="/login?error"
            username-parameter="username" password-parameter="password" />
        <security:logout logout-success-url="/login?logout" />
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userServiceImpl">
                <security:password-encoder ref="bcryptEncoder" />
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="userServiceImpl" class="com.emusicstore.service.impl.UserServiceImpl" />

    <bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" >
    <constructor-arg name="strength" value="11" />
    </bean>

Login.jsp

<form name="loginForm" action="<c:url value="/j_spring_security_check" />" method="post">

                <c:if test="$not empty error">
                    <div class="error" style="color: #ff0000;">$error</div>
                </c:if>

                <div class="form-group">
                    <label for="username">Email : </label>
                    <input type="text" id="username" name="username" class="form-control" />
                </div>
                <div class="form-group">
                    <label for="password">Passwrod:</label>
                    <input type="password" id="password" name="password" class="form-control" />
                </div>
                <input type="submit" value="Submit" class="btn btn-default">
                <input type="hidden" name="$_csrf.parameterName" value="$_csrf.token" />
            </form>

UserServiceImpl.java

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.jaas.AuthorityGranter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.emusicstore.dao.UserDao;
import com.emusicstore.model.Users;
import com.emusicstore.service.UserService;
@Service
@Transactional
@Qualifier("userServiceImpl")
public class UserServiceImpl implements UserDetailsService

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String useremail)
            throws UsernameNotFoundException 
        Users user = userDao.findByUserEmail(useremail);
        if(user == null)
            throw new UsernameNotFoundException("UserName or Password Invalid.");
        
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), user.getEnabled(), true, true, true, getGrantedAuthorities(userDao.getUserRole(user.getUsersId())));
    

    private final List<GrantedAuthority> getGrantedAuthorities(final List<String> roleList) 
        final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        for (final String role : roleList) 
            authorities.add(new SimpleGrantedAuthority(role));
        
        return authorities;


控制台错误如下:

错误: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - 尝试对用户进行身份验证时发生内部错误。 org.springframework.security.authentication.InternalAuthenticationServiceException 在 org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:110) 在 org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132) 在 org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) 在 org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177) 在 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:92) 在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) 在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 在 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 在 org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096) 在 org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(未知来源) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(未知来源) 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 在 java.lang.Thread.run(Unknown Source) 引起: java.lang.NullPointerException 在 com.emusicstore.service.impl.UserServiceImpl.loadUserByUsername(UserServiceImpl.java:33) 在 org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:102) ... 35 更多

请帮助我克服上述错误。

非常感谢。

【问题讨论】:

【参考方案1】:

我相信它在您的自定义代码中是一个简单的 NullPointerException。在UserServiceImpl.java的33处打断点,检查一下。

引起:java.lang.NullPointerException at com.emusicstore.service.impl.UserServiceImpl.loadUserByUsername(UserServiceImpl.java:33)

【讨论】:

【参考方案2】:
 Users user = userDao.findByUserEmail(useremail);

userDao.findByUserEmail(useremail); 以上返回空值。

【讨论】:

我错误地将这段代码 放在 ApplicationContext.xml 中,运行时 spring 找不到服务自动装配,但实际上它应该在我的 dispatcher-servlet.xml 下。谢谢。【参考方案3】:

就我而言,this link 提供了帮助。这是快照问题。

【讨论】:

以上是关于在 Spring Security 中使用 UserDetailSservice 使用电子邮件进行登录身份验证的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Spring Security 中验证 url 模式的角色

将领域角色和资源角色与 Keycloak/Spring Security 一起使用

在视图中用spring security访问当前登录的用户用户名

Spring Security登录成功后如何处理用户信息

Spring Security应用开发(15)层次化角色体系

使用 Spring Security 配置 HTTP 页面和 HTTPS 页面