让多个用户获得基本身份验证,弹出启动安全性

时间:2018-03-14 13:35:18

标签: java spring-boot encoding spring-security bcrypt

我有一个用户列表,我想在我的基本身份验证中使用它们。

我的代码目前看起来像这样:

@Configuration
@EnableWebSecurity
public class BasicAuthConfig extends WebSecurityConfigurerAdapter {

  @Bean
  public PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
  @Autowired
  private ConfigService configService;
  // Authentication : User --> Roles
  // NoOpPasswordEncoder has been deprecated in Spring security so {noop} is being used to avoid errors
  protected void configure(AuthenticationManagerBuilder auth)
    throws Exception {
    auth.inMemoryAuthentication().passwordEncoder(passwordEncoder())
      .withUser("someuser")
        .password("somepassword")
        .roles("USER");
  }

  // Authorization : Role -> Access
  protected void configure(HttpSecurity http) throws Exception {
    http
      .httpBasic()
        .and().authorizeRequests()
          .antMatchers("/actuator/**")
            .permitAll()
          .antMatchers("/tokenservice/**")
            .hasRole("USER")
          .antMatchers("/")
            .permitAll()
        .and().csrf()
        .disable()
          .headers()
          .frameOptions()
        .and().disable()
          .sessionManagement()
          .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  }}

我想替换" someuser"和#34; somepassword"使用我的用户列表中的用户名和密码。目前,我可以使用configService.getCOnfigurations().getUsers()获取列表。 用户只有一个用户名和密码,两个字符串。如何将所有用户名和所有密码都放入.withUser()

**编辑 我在配置中做了一个简单的for循环,应该这样做,但每当我尝试发布到我的API时,它都说org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder:99 - Encoded password does not look like BCrypt

我使用在线bcrypt生成器生成密码,它们看起来像这样

<?xml version="1.0" encoding="UTF-8"?>
<Configurations>
    <Port>8007</Port>
    <EnableHttps>true</EnableHttps>
    <KeyStorePath>classpath:ssl-server.jks</KeyStorePath>
    <KeyPass>changeit</KeyPass>
    <TokenTtlMillis>15000</TokenTtlMillis>
  <Users Username="user1">
      <Password>$2y$10$.8VQR6tJub5uVdVLByItQO8QYGZVuWPhLuBUTQSDJAvVpLAUmuqZ2</Password>
  </Users>
  <Users Username="user2">
    <Password>$2y$10$r/CQz7PZp5banmSzr9OiDe2Kxrda4BhXIBXvvouRnm1w3M72wLQj.</Password>
  </Users>
</Configurations>

密码只是简单的密码和密码2

3 个答案:

答案 0 :(得分:2)

以Claudio对DaoAuthenticationProvider

的回答为基础
@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
    authenticationProvider.setUserDetailsService(userDetailsService());
    authenticationProvider.setPasswordEncoder(passwordEncoder());
    return authenticationProvider;
}

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

@Override
protected UserDetailsService userDetailsService() {
    return new MyUserDetailsService();
}

UserDetailsService是代码的真正含义。您将提供从XML读取的接口的自定义实现。假设您有方法getPassword(String username)

// Adding this import to demontrate where "User" is coming from
import org.springframework.security.core.userdetails.User;

public class MyUserDetailsService implements UserDetailsService {

    @Override
    public User loadUserByUsername(String username) {
        return new User(username, getPassword(username), Arrays.asList(new SimpleGrantedAuthority("USER")));
    }

    private String getPassword(String username) {
        // Get password from your XML
    }
}

至于你的BCrypt问题,password哈希给了我一个无效的盐修订错误。尝试直接使用您的应用程序哈希,例如:

public static void main(String[] args) {
    System.out.println(new BCryptPasswordEncoder().encode("password"));
}

或者在每行传入一个带密码的文件(使用Java 8):

public static void main(String[] args) throws IOException {
    if (args.length != 1) {
        System.out.println("Requires 1 parameter that points to a file.");
        System.exit(1);
    }
    File f = new File(args[0]);
    if (!f.isFile()) {
        System.out.println("Not a file: " + f);
        System.exit(1);
    }
    PasswordEncoder encoder = new BCryptPasswordEncoder();
    try (Stream<String> lines = Files.lines(f.toPath())) {
        lines.map(encoder::encode)
                .forEach(System.out::println);
    }
}

这将为您提供Spring生成的哈希值,然后您可以将其插入到XML中。

答案 1 :(得分:0)

您可以在DaoAuthentificationProvider中声明WebSecurityConfigurerAdapter,如下所示:

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
    authenticationProvider.setUserDetailsService(userDetailsService());
    authenticationProvider.setPasswordEncoder(passwordEncoder());
    return authenticationProvider;
}

并为其实施passwordEncoderuserDetailsService, 您必须为其实现相应的接口及其方法。

然后,您可以在authenticationProvider班级中分配WebSecurityConfigurerAdapter,如下所示:

@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService());
    auth.authenticationProvider(authenticationProvider());
}

这样,您的UserDetailService将提供所有可用用户及其凭据,您无需在安全配置中担心这一点。

通过这种方式,您可以以任何您想要的方式存储凭据(简单文件,像MongoDB这样的nosql DB等),甚至可以更改该实现,而不会影响您使用spring security进行身份验证的方式。

您的UserDetailService应该看起来像这样:

public class SecUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User user = userRepository().findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        } else {
            Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
            grantedAuthorities.add(new SimpleGrantedAuthority(user.getRole().getName()));

            return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(),
                    grantedAuthorities);
        }
    }
}

这里我使用了UserRepository来处理从您选择的存储中加载所有用户的问题。例如。如果您决定将其存储在文件中,它将从文件中加载所有用户及其密码,并提供方法findByUsername,如果找到具有匹配名称的对象,则返回User对象。如果需要,您的存储库还可以负责删除用户或修改其名称。

答案 2 :(得分:0)

我在spring boot 2.x上实现了这一点,在服务器启动时从控制台获取用户凭据;您可以轻松地将其更改为从文件或任何其他来源加载用户:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger log = LogManager.getLogger();

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Note: 
        // Use this to enable the tomcat basic authentication (tomcat popup rather than spring login page)
        // Note that the CSRf token is disabled for all requests
        log.info("Disabling CSRF, enabling basic authentication...");
        http
        .authorizeRequests()
            .antMatchers("/**").authenticated() // These urls are allowed by any authenticated user
        .and()
            .httpBasic();
        http.csrf().disable();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        log.info("Setting in-memory security using the user input...");

        String username = null;
        String password = null;

        System.out.println("\nPlease set the admin credentials for this web application (will be required when browsing to the web application)");
        Console console = System.console();

        // Read the credentials from the user console: 
        // Note: 
        // Console supports password masking, but is not supported in IDEs such as eclipse; 
        // thus if in IDE (where console == null) use scanner instead:
        if (console == null) {
            // Use scanner:
            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.print("Username: ");
                username = scanner.nextLine();
                System.out.print("Password: ");
                password = scanner.nextLine();
                System.out.print("Confirm Password: ");
                String inputPasswordConfirm = scanner.nextLine();

                if (username.isEmpty()) {
                    System.out.println("Error: user must be set - please try again");
                } else if (password.isEmpty()) {
                    System.out.println("Error: password must be set - please try again");
                } else if (!password.equals(inputPasswordConfirm)) {
                    System.out.println("Error: password and password confirm do not match - please try again");
                } else {
                    log.info("Setting the in-memory security using the provided credentials...");
                    break;
                }
                System.out.println("");
            }
            scanner.close();
        } else {
            // Use Console
            while (true) {
                username = console.readLine("Username: ");
                char[] passwordChars = console.readPassword("Password: ");
                password = String.valueOf(passwordChars);
                char[] passwordConfirmChars = console.readPassword("Confirm Password: ");
                String passwordConfirm = String.valueOf(passwordConfirmChars);

                if (username.isEmpty()) {
                    System.out.println("Error: Username must be set - please try again");
                } else if (password.isEmpty()) {
                    System.out.println("Error: Password must be set - please try again");
                } else if (!password.equals(passwordConfirm)) {
                    System.out.println("Error: Password and Password Confirm do not match - please try again");
                } else {
                    log.info("Setting the in-memory security using the provided credentials...");
                    break;
                }
                System.out.println("");
            }
        }

        // Set the inMemoryAuthentication object with the given credentials:
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        if (username != null && password != null) {
            String encodedPassword = passwordEncoder().encode(password);
            manager.createUser(User.withUsername(username).password(encodedPassword).roles("USER").build());
        }
        return manager;
    }

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