集成 Spring Security:身份验证自定义 UserDetailsS​​ervice

Posted

技术标签:

【中文标题】集成 Spring Security:身份验证自定义 UserDetailsS​​ervice【英文标题】:Integration Spring Security : authentification Custom UserDetailsService 【发布时间】:2015-10-12 03:53:04 【问题描述】:

在使用 Spring MVC + Hibernate / JPA 构建应用程序之后

我想集成安全弹簧

在身份验证期间,我遇到“不执行查询”的问题

这里是我的 Security-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


  <!-- Activates various annotations to be detected in bean classes -->
    <context:annotation-config />

    <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
     For example @Controller and @Service. Make sure to set the correct base-package -->
    <context:component-scan base-package="com.pfe.*" />



<security:global-method-security pre-post-annotations="enabled"></security:global-method-security>

<security:http auto-config="true" use-expressions="true">
<security:session-management invalid-session-url="/login?time=1">
<security:concurrency-control max-sessions="1" expired-url="/login?time=1"/>

</security:session-management>
<security:form-login 
login-page="/login" 
login-processing-url="/login.do" 
default-target-url="/home" 
always-use-default-target="true"
authentication-failure-url="/login?error=true"
username-parameter="username"
password-parameter="password"/>

<security:logout
logout-url="/logout"
logout-success-url="/login?out=true"
delete-cookies="JSESSIONID"
invalidate-session="true"/>

<security:intercept-url pattern="/login*" access="permitAll"/>
<security:intercept-url pattern="/home*" access="permitAll"/>

</security:http>


 <bean id="encoder"  
  class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">  
  <constructor-arg name="strength" value="10" />  
 </bean> 
<security:authentication-manager alias="authenticationManager">
            <security:authentication-provider user-service-ref="loginService">
                <security:password-encoder ref="encoder"/>
           </security:authentication-provider>

</security:authentication-manager>

</beans>

这里是我的登录服务

import java.util.List;

import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.pfe.dao.repositories.UserRepository;
import com.pfe.entities.UserModel;
import com.pfe.services.LoginService;



@Service("loginService")
@Transactional
public class LoginServiceImp implements  UserDetailsService ,LoginService

    @Autowired
    private UserRepository Repository;






        @Override
     public UserDetails loadUserByUsername( String username ) throws UsernameNotFoundException
        
        /*  String p = "12345";
            Md5PasswordEncoder pe= new Md5PasswordEncoder();
            String encPassword =pe.encodePassword("123456",null);
        */  
             System.out.println("heeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeere");
            UserModel user = Repository.findUserByUsername_isEnable(username);


            System.out.println("okkkkkkkkk");
             if( user == null )
                    throw new UsernameNotFoundException( "Oops!" );

            System.out.println("--------------------------------");
            System.out.println(user.getUsername());
            System.out.println(user.getPassword());
            System.out.println("--------------------------------");

            List<SimpleGrantedAuthority> authorities =  user.getListAcces_String() ;

            return new User ( user.getUsername(), user.getPassword(), authorities );
        




这里是用户存储库

import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;

import org.springframework.stereotype.Repository;

import com.pfe.dao.IDAOUser;
import com.pfe.entities.UserModel;

@Transactional
@Repository("userRepository")
public class UserRepository extends ImpJPAGenericDAO<UserModel>  implements IDAOUser 


  public UserModel findUserByUsername_isEnable(String username) 


        System.out.println("okkkkkkkkkheeeeeeeeeeeeeeeeeeeeeeeeeeere");

        UserModel result = null ;
        TypedQuery<UserModel> query = em.createQuery("SELECT myuser FROM User myuser where myuser.username =:login",UserModel.class);

        query.setParameter("login", username);


        System.out.println("okkkkkkkkkheeeeeeeeeeeeeeeeeeeeeeeeeeere2");





        try 
         result = query.getSingleResult() ;
         catch (NoResultException ne)
            return null ;
        

        return result ;
    

执行:

heeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeere
okkkkkkkkkheeeeeeeeeeeeeeeeeeeeeeeeeeere

跟踪:

20:15:40,401 DEBUG LogicalConnectionImpl:3794 - Obtaining JDBC connection
20:15:40,401 DEBUG DriverManagerDataSource:162 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/mybd?useUnicode=yes&characterEncoding=UTF-8]
20:15:40,409 DEBUG LogicalConnectionImpl:3794 - Obtained JDBC connection
20:15:40,409 DEBUG JdbcTransaction:3554 - initial autocommit status: true
20:15:40,409 DEBUG JdbcTransaction:3554 - disabling autocommit
20:15:40,410 DEBUG ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler:423 - Starting resource local transaction on application-managed EntityManager [org.hibernate.ejb.EntityManagerImpl@ded21c]
20:15:40,411 DEBUG ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler:400 - Joined local transaction
20:15:40,441 DEBUG QueryTranslatorImpl:3799 - parse() - HQL: SELECT myuser FROM User myuser where myuser.username =:login
20:15:40,446 DEBUG QueryTranslatorImpl:3554 - --- HQL AST ---
 \-[QUERY] Node: 'query'
    +-[SELECT_FROM] Node: 'SELECT_FROM'
    |  +-[FROM] Node: 'FROM'
    |  |  \-[RANGE] Node: 'RANGE'
    |  |     +-[IDENT] Node: 'User'
    |  |     \-[ALIAS] Node: 'myuser'
    |  \-[SELECT] Node: 'SELECT'
    |     \-[IDENT] Node: 'myuser'
    \-[WHERE] Node: 'where'
       \-[EQ] Node: '='
          +-[DOT] Node: '.'
          |  +-[IDENT] Node: 'myuser'
          |  \-[IDENT] Node: 'username'
          \-[COLON] Node: ':'
             \-[IDENT] Node: 'login'

20:15:40,446 DEBUG ErrorCounter:3794 - throwQueryException() : no errors
20:15:40,474 DEBUG HqlSqlBaseWalker:3809 - select << begin [level=1, statement=select]
20:15:40,487 DEBUG JpaTransactionManager:843 - Initiating transaction rollback
20:15:40,488 DEBUG JpaTransactionManager:488 - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1060d0]
20:15:40,488 DEBUG AbstractTransactionImpl:3554 - rolling back
20:15:40,488 DEBUG JdbcTransaction:3554 - rolled JDBC Connection
20:15:40,489 DEBUG JdbcTransaction:3554 - re-enabling autocommit
20:15:40,492 DEBUG AbstractTransactionImpl:3554 - rolling back
20:15:40,493 DEBUG JdbcTransaction:3554 - rolled JDBC Connection
20:15:40,493 DEBUG JdbcTransaction:3554 - re-enabling autocommit
20:15:40,493 DEBUG JpaTransactionManager:548 - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@1060d0] after transaction
20:15:40,494 DEBUG EntityManagerFactoryUtils:328 - Closing JPA EntityManager
20:15:40,494 DEBUG LogicalConnectionImpl:3794 - Releasing JDBC connection
20:15:40,494 DEBUG LogicalConnectionImpl:3794 - Released JDBC connection
20:15:40,496 DEBUG DefaultListableBeanFactory:246 - Returning cached instance of singleton bean 'org.springframework.security.core.session.SessionRegistryImpl#0'
20:15:40,496 DEBUG UsernamePasswordAuthenticationFilter:340 - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: org.hibernate.hql.internal.ast.QuerySyntaxException: User is not mapped [SELECT myuser FROM User myuser where myuser.username =:login]
20:15:40,496 DEBUG UsernamePasswordAuthenticationFilter:341 - Updated SecurityContextHolder to contain null Authentication
20:15:40,496 DEBUG UsernamePasswordAuthenticationFilter:342 - Delegating to authentication failure handlerorg.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@1760a96
20:15:40,497 DEBUG SimpleUrlAuthenticationFailureHandler:67 - Redirecting to /login?error=true

【问题讨论】:

您能详细说明您遇到的问题吗? “不执行查询”是什么意思?怎么了?你期望会发生什么?你得到结果吗?您是否获得了堆栈跟踪(如果有,您能否提供完整的)? 我既没有结果也没有错误,它停在这一行 'TypedQuery query = em.createQuery("SELECT myuser FROM User myuser where myuser.username =:login" ,UserModel.class); query.setParameter("登录", 用户名);' 如果您为 Hibernate 启用调试日志记录,此时您在日志中看到了什么?你确定它不只是真的很慢吗?见***.com/questions/9914271/… 您是否看到任何休眠日志记录(如果没有,您没有正确配置日志记录)?请发布休眠日志。如果您更改 Query 的创建以创建针对不同域对象的查询,会发生什么情况?用户模型是什么样的? 【参考方案1】:

根据日志,它不是“停止”,而是抛出异常。日志状态:

20:15:40,496 DEBUG UsernamePasswordAuthenticationFilter:340 - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: org.hibernate.hql.internal.ast.QuerySyntaxException: User is not mapped [SELECT myuser FROM User myuser where myuser.username =:login]

具体来说:

QuerySyntaxException: 用户未映射 [SELECT myuser FROM User myuser 其中 myuser.username =:login]

我的猜测是您打算在查询中使用 UserModel 而不是 User。具体来说,您应该在 UserRepository 中使用以下内容:

TypedQuery<UserModel> query = em.createQuery("SELECT myuser FROM UserModel myuser where myuser.username =:login",UserModel.class);

【讨论】:

谢谢!!我是初学者:( @LhbLaura 没问题。如果您不喜欢手动执行 JPA,您可以考虑使用 Spring Data JPA,它会使用一些约定自动为您创建查询(包括分页、排序和自定义属性)。请参阅docs.spring.io/spring-data/jpa/docs/current/reference/html 如果您正在执行 REST,您还可以添加一个简单的注释,它将作为 REST 端点与 Spring Data REST docs.spring.io/spring-data/rest/docs/current/reference/html

以上是关于集成 Spring Security:身份验证自定义 UserDetailsS​​ervice的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 3 身份验证与 Hibernate 3(JPA) 注释的集成

在corda中使用spring security的基本身份验证

Spring Security (4.0.1) 与 AngularJS 的集成。每次用户输入无效凭据时都会弹出基本身份验证

Spring Security基础原理

Spring session 与 spring security saml 的集成

Spring Security 和自定义外部身份验证