在 Mongo Db 中更新相关文档后 Spring 用户身份验证不起作用

Posted

技术标签:

【中文标题】在 Mongo Db 中更新相关文档后 Spring 用户身份验证不起作用【英文标题】:Spring user authentication does not work after updating related document in Mongo Db 【发布时间】:2017-10-05 20:42:17 【问题描述】:

我在使用 Spring Security 和 Mongo Db 时遇到了一种相当奇怪的行为。

我有一个在 Mongo 中持久存在的客户用户实体:

@Document(collection = "user")
public class User 

  @Id
  private ObjectId id;

  private String username;

  ...

我实现了一个 UserService,它允许以一种相当常见的方式持久化这些实体:

@Service
public class UserServiceImpl implements UserService 
   @Override
   public void save(User user) 
     user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
     user.setAccountNonExpired(true);
     user.setAccountNonLocked(true);
     user.setCredentialsNonExpired(true);
     user.setEnabled(true);
     user.addRole(roleRepository.findByName("USER"));
     userRepository.save(user);
  
  ...

我还有一个 SecurityService 实现:

@Service
public class SecurityServiceImpl implements SecurityService 
    @Override
    public void autologin(String username, String password)  ... 

还有一个 UserDetailsS​​ervice:

@Service
public class UserDetailsServiceImpl implements UserDetailsService 

   @Override
   @Transactional(readOnly = true)
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
       User user = userRepository.findByUsername(username);
       if (user == null) 
          user = userRepository.findByEmail(username);
          if (user == null) 
             log.warn("Login attempt with unknown username");
             throw new UsernameNotFoundException("not found");
                
       
       Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
       for (Role role : user.getRoles()) 
         grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));


return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
  user.isEnabled(), user.isAccountNonExpired(),
  user.isCredentialsNonExpired(), user.isAccountNonLocked(),
  grantedAuthorities);

在我的控制器中,我有类似的东西

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(HttpServletRequest request, Model model, String error, 
                  String logout, Principal principal)  ... 

这很好用。我可以注册用户,登录,注销,重新登录。信息保留在 Mongo 中并正确加载。一切似乎都很好,直到我尝试实施重置密码..

我在我的 UserServiceImpl 类中实现了简单的方法来执行此操作,但即使简单地使用以下实现,也会发生相当奇怪的行为:

@Override
public void updateUser(User user)       
  userRepository.save(user);

调用此方法后,如果我退出,我将无法再登录。我可以重新启动我的 spring-boot 应用程序,但仍然无法登录。

这很奇怪,因为我可以看到 Mongo 中的 JSON 文档没有改变。当我意识到如果我在 Mongo 中手动编辑相关文档(不执行任何实际更改,只需删除和添加相同的字符并保存它)之后,这变得很疯狂,然后登录再次工作!

如果有帮助:

MongoDB shell 版本:3.2.13,spring boot 1.4.1.RELEASE

有什么办法解决这个问题吗?

【问题讨论】:

【参考方案1】:

不确定,但我认为您在更新用户时错过了一件小事。 您在创建用户时加密了密码

user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));

我假设您在更新密码时也在更新密码。 但是更新用户时没有密码加密,正如我在您的 updateUser 方法中看到的那样(除非您在调用此方法之前已加密密码)。

如果我是正确的,那么我的建议是在更新用户数据时避免更新密码,并使用不同的方法来更改密码。

【讨论】:

以上是关于在 Mongo Db 中更新相关文档后 Spring 用户身份验证不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用官方 C# 驱动程序在 Mongo DB 中进行更新插入

学习mongo系列修改器($inc/$set/$unset/$push/$pop/upsert)

如何在Mongo DB中使用arrayElemAt获取当前文档值

如何在其中一个字段 Mongo Db [重复] 中检索具有最大值的文档

Kafka mongo db源连接器不起作用

mongo db:从对象数组中获取子数组,其值在单个文档的范围内