首页 > 解决方案 > 未调用自定义 Spring UserDetailsS​​ervice

问题描述

我正在尝试为当前登录的用户添加一些自定义数据,所以我发现我可以实现自己的 UserDetailsS​​ervice 并将其插入 Spring,但它从未被调用,我总是将 Principal 作为用户名字符串。

我有我的 UserDetailsS​​ervice 实现:

@Service
public class UserDetailServiceImpl implements UserDetailsService {

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    ...
  }
}

我对 UserDetails 的实现:

import org.springframework.security.core.userdetails.User;

public class LoggedInUser extends User {
...
}

并尝试以多种方式在配置(SecurityConfiguration)中设置它:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
      @Autowired
      private CustomAuthenticationProvider customAuthProvider;
      @Autowired
      private UserDetailsService userDetailServiceImpl;
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthProvider);
        auth.userDetailsService(userDetailServiceImpl).passwordEncoder(passwordService.getPasswordEncoder());
      }
...
}

或者

@Autowired
  protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(customAuthProvider);
    auth.userDetailsService(userDetailServiceImpl).passwordEncoder(passwordService.getPasswordEncoder());
  }

或者

@Override
  @Bean
  public UserDetailsService userDetailsService() {
    return new UserDetailServiceImpl();
  }

没有任何效果......我尝试了多种方式检索用户信息:

  1. 在带有@AuthenticationPrincipal 的控制器中,我得到空值
  2. 在服务中(我得到无效的演员错误):

    身份验证身份验证 = SecurityContextHolder.getContext().getAuthentication(); (LoggedInUser) authentication.getPrincipal()

知道为什么它不起作用吗?我的 impl 类是否在其他地方被默认覆盖?我试图查看日志(logging.level.org.springframework.security=TRACE)但没有运气:/我可以登录,这很好,只是主体数据总是只有用户名字符串而不是我的类。

标签: javaspringspring-bootspring-securityuserdetailsservice

解决方案


ILya Cyclone 的评论是找出问题所在的关键,CustomAuthenticationProvider再次检查后我注意到在返回数据时您可以指定Principal不需要只是用户名,但您可以在UserDetails那里添加您的自定义,因为该自定义UserDetailsService不是调用,这是我假设它总是会被调用的错误。

所以最后这足以让 customAuthenticationProvider有 custom UserDetails

@Service
public class CustomAuthenticationProvider implements AuthenticationProvider {

  @Autowired
  private UserService userService;

  @Autowired
  private PasswordService passwordService;

  @Override
  public Authentication authenticate(Authentication auth) throws AuthenticationException {
    String username = auth.getName();
    String password = auth.getCredentials().toString();

    User user = userService.getUserWithPermissionsByName(username);
    if (user == null) {
      throw new BadCredentialsException("invalid_username_or_pass");
    }

    if (!passwordService.passwordsMatch(password, user.getPassword())) {
      throw new BadCredentialsException("invalid_username_or_pass");
    }

    String[] permissions = user.getPermissions().stream().map((p) -> p.getName()).toArray(String[]::new);
    List<GrantedAuthority> grantedAuths = AuthorityUtils.createAuthorityList(permissions);
    return new UsernamePasswordAuthenticationToken(new LoggedInUser(user.getName(), user.getPassword(), true, true, true, true, grantedAuths, user.getId()),
        password, grantedAuths);
  }

  @Override
  public boolean supports(Class<?> auth) {
    return auth.equals(UsernamePasswordAuthenticationToken.class);
  }
}

推荐阅读