1

我一直坚持使用 Spring Security 在 SpringMVC 中创建有用的表单登录。我是这方面的新手,也是Hibernate。我想创建简单的表单登录,它可以提供对我的 Web 应用程序的访问。

我使用 SpringSource Tool Suite 创建了我的项目并选择了 Spring Template Project。它使用 Maven,我还通过带有注释的 Hibernate 类生成了hibernate.cfg.xml. 在我的数据库 (HSQLDB) 中,我有三个表:users、roles 和 users_roles。第三个包含 user_id 和 role_id,因此它存储有关用户角色的信息。我已经通过 Hibernate 成功生成了类。

我已经开始编写实现 UserDetailsS​​ervice 的类。但我不知道如何正确地做到这一点。在spring-security.xml我已经定义了这样的bean:

<bean id="userDetailsService" class="hutter.pl.services.HutterUserDetailsService" />

我想通过 sha-256 和 saltSource 使用散列。

<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
    <property name="userPropertyToUse" value="username"/>
</bean>

<security:authentication-manager>   
    <security:authentication-provider user-service-ref="userDetailsService">
        <security:password-encoder hash="sha-256">
            <security:salt-source ref="saltSource" />
        </security:password-encoder> 
    </security:authentication-provider>
</security:authentication-manager>

我是否应该使用此解决方案:https ://stackoverflow.com/a/1654488/845220 ?Hibernate 生成了如下类:RolesHome、Roles、Users、UsersHome、UsersRoles、UsersRolesHome。但我真的不知道如何使用这些 Hibernates 类来授权用户。

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {   
        UsersHome usersHome = new UsersHome();
       //Users user = ...       
       //...            
       return null;     
    }   
}

你能给我一些提示吗?

编辑: 我试图向类添加public Users findByLogin(String login)方法UsersHome

   public Users findByLogin(String login) {
    log.debug("getting Users instance with login: " + login);
    try {
        Users instance = entityManager.find(Users.class, login);
        log.debug("get successful");
        return instance;
    } catch (RuntimeException re) {
        log.error("get failed", re);
        throw re;
    }
}

我的 UserDetailsS​​ervice 的主体看起来像:

UsersHome usersHome = new UsersHome();
Users user = usersHome.findByLogin(username);

但我有例外:

 ERROR: my.package.dao.UsersHome - get failed
 java.lang.NullPointerException
at my.package.dao.UsersHome.findByLogin(UsersHome.java:72)
at my.package.services.HutterUserDetailsService.loadUserByUsername(MyUserDetailsService.java:19)
4

1 回答 1

7

我认为您不需要自己实现 UserService 。您可以将 ajdbc-user-service与数据源一起使用:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://localhost:3306/mydb" />
  <property name="username" value="root" />
  <property name="password" value="password" />
</bean>

<authentication-manager>
  <authentication-provider>
    <jdbc-user-service data-source-ref="dataSource"
      users-by-username-query="select username,password, enabled from users where username=?"
      authorities-by-username-query="select u.username, ur.authority from users u, user_roles ur  where u.user_id = ur.user_id and u.username =?" 
    />
  </authentication-provider>
</authentication-manager>

使用这些属性users-by-username-queryusers-by-username-query您可以定义 spring security 应该用来从数据源接收用户和权限的查询。

UserService如果有必要实施你自己的

  • 您想返回自定义的 UserDetails 对象(您可以稍后通过 访问SecurityContextHolder
  • 用户对象和权限的接收过于复杂和/或无法通过简单的查询来定义jdbc-user-service

UserDetailsS​​ervice 的可能实现如下所示:

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

  @PersistenceContext
  private EntityManager entityManager;

  @Transactional(readOnly = true)
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {   

    // this works only if username is the primary key of user
    // if thats not the case you have to create a query object to receive the user by username
    User user = entityManager.find(User.class, username); 

    List<GrantedAuthority> roles = .... // get roles for user, depends on your table structure

    if (user == null) {
      // user not found
      throw new UsernameNotFoundException();
    }
    return new MyUserDetails(user, roles);
  }

  private static class MyUserDetails implements UserDetails {
    private User user;
    private List<Role> roles;

    public MyUserDetails(Usere user, List<GrantedAuthority> roles) {
      this.user = user;
      this.roles = roles;
    }

    public Collection<GrantedAuthority> getAuthorities() {
      return roles;
    }

    public String getPassword() {
      return user.getPassword();
    }

    public String getUsername() {
      return user.getUsername();
    }

    // return true for the missing boolean methods..
  }
}

(语法未选中)

对于第一次测试,它可以帮助禁用密码编码器并将未加密的密码存储在数据库中。这避免了由于密码编码器配置错误而导致您的身份验证不起作用的问题。运行用户服务后,您可以再次添加 PasswordEncoder 并将散列密码存储在数据库中。

希望能帮助到你 :-)

于 2012-07-08T10:06:10.717 回答