首页 > 解决方案 > 我在哪里从 Spring Security 中获取“用户名”值以传递给 UserDetailsS​​ervice 接口的 loadUserByUsername(String username) 方法

问题描述

我试图通过基于用户名和密码对用户进行身份验证来从数据库中获取用户。我正在使用基本身份验证来执行此操作。我在其余 api 的授权标头中发送用户名和密码

在我的控制器中,getUser() 方法调用 UserService 类的 getuser() 方法

 @GetMapping("/user/self")
public ResponseEntity<UserDto> getUser() {
    UserDto UserDto = userService.getUser();
    return new ResponseEntity<>(UserDto, HttpStatus.OK);
}

@PutMapping("/user/self")
public ResponseEntity<User> updateUser(@Valid @RequestBody Map<String, String> userMap, Principal principal) {
    String username = principal.getName();
    String firstname = userMap.get("firstName");
    String lastName = userMap.get("lastName");
    String password = BCrypt.hashpw(userMap.get("password"), BCrypt.gensalt(10));
    User user = userService.getUserByUserName(username);
    user.setFirstName(firstname);
    user.setLastName(lastName);
    user.setPassword(password);
    userService.save(user);
    return new ResponseEntity<>(user, HttpStatus.NO_CONTENT);
}

UserService 类实现 UserDetailsS​​ervice 并覆盖需要将用户名作为参数传递的 loadUserByUsername 方法。我的问题是:如何从我的控制器调用的 UserService 类中将用户名传递给 loadUserByUsername() 方法。用户名值在哪里?我的理解是-身份验证对象包含当用户键入其凭据并发送其请求时传递给身份验证对象的用户凭据,我如何检索此用户名值

 @Service
     public class UserService implements UserDetailsService {

@Autowired
UserRepository userRepository;

public UserDto save(User user) {
    String hashedPassword = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt(10));
    user.setPassword(hashedPassword);
    userRepository.save(user);
    UserDto userDto = new UserDto();
    userDto.setId(user.getId());
    userDto.setFirstName(user.getFirstName());
    userDto.setLastName(user.getLastName());
    userDto.setUserName(user.getUserName());
    userDto.setAccountUpdatedAt(user.getAccountUpdatedAt());
    userDto.setAccountCreatedAt(user.getAccountCreatedAt());
    return userDto;
}

@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
    User user = userRepository.findByUserName(userName);
    if (user == null) {
        throw new UsernameNotFoundException(userName + "was not found");
    }
    return new UserPrincipal(user);
}

这是我的存储库代码:

 @Repository
    public interface UserRepository extends CrudRepository<User, Long> {

User findByUserName(String userName);
   }

这是我的验证码:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
DataSource dataSource;
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
UserService userService;


@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder());

}


@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable();
    http.authorizeRequests().antMatchers("/v1/user").permitAll()
            .antMatchers("/v1/user/self").authenticated().and().httpBasic()
            .authenticationEntryPoint(authenticationEntryPoint);
 }
}

标签: springspring-bootspring-securityspring-data-jpabasic-authentication

解决方案


如果您处理 JPA,那么在您的情况下,您必须使用userDetailsService而不是jdbcauthentication,因此您的安全类将如下所示:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private  UserService userService;
    
    public SecurityConfig(UserService userService){
        this.userService = userService;
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder(10); // Number of rounds 
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.userService).passwordEncoder(passwordEncoder());
    }
}

然后您可以在UserService类中自定义身份验证以满足业务需求,如下例所示:

@Service
public class UserService implements UserDetailsService {

    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository){
        this.userRepository = userRepository;
    }

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

        Optional<User> user = userRepository.findByUsername(username);

        if(user.isPresent()){
            log.info("cretaed under User service : " + user.get());
            return user.get();
        }

        throw new UsernameNotFoundException("empty or invalud user");
    }
}

此外,不要忘记findByUsername在您的存储库中创建方法也不要忘记org.springframework.security.core.userdetails.UserDetails在您的模块类中实现:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    Optional<User> findByUsername(String name);
}

推荐阅读