我有一个用户列表,我想在我的基本身份验证中使用它们。
我的代码目前看起来像这样:
@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
答案 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;
}
并为其实施passwordEncoder
和userDetailsService
,
您必须为其实现相应的接口及其方法。
然后,您可以在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();
}
}