Java 甚至可以只使用Spring Security和Data JPA,通过加密实现数据库支持的登录过程吗?
正如标题所述,我正在尝试实现一些东西,在这一点上,我甚至不确定是否可能以我想象的方式实现它。我想要一个非常简单的、数据库支持的注册和登录过程,以便向不同的用户显示不同的页面内容。所以它应该是这样工作的:Java 甚至可以只使用Spring Security和Data JPA,通过加密实现数据库支持的登录过程吗?,java,spring,spring-boot,encryption,spring-security,Java,Spring,Spring Boot,Encryption,Spring Security,正如标题所述,我正在尝试实现一些东西,在这一点上,我甚至不确定是否可能以我想象的方式实现它。我想要一个非常简单的、数据库支持的注册和登录过程,以便向不同的用户显示不同的页面内容。所以它应该是这样工作的: 用户在注册页面上注册,执行所有检查并 用户已创建 密码用Bcrypt加密,用户名和密码为 使用Spring数据JPA存储在数据库中 用户通过“标准”Spring安全登录表单登录 UserDetailsService的自定义实现获取用户名的数据库条目 Spring security比较用
- 用户在注册页面上注册,执行所有检查并 用户已创建
- 密码用Bcrypt加密,用户名和密码为
使用Spring数据JPA存储在数据库中 - 用户通过“标准”Spring安全登录表单登录
的自定义实现获取用户名的数据库条目UserDetailsService
- Spring security比较用户的密码和日志
- 成功登录后,我将获得一个主体,并能够显示
基于此的内容
UserDetailsService
,如注释中所述,密码实际上是一个有效的60个字符的Bcrypt
package com.example.demo;
import...
import java.util.Optional;
@Service("myUserDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Optional<UserDB> userDB = userRepository.findById(s);
User user = null;
if (userDB.isPresent()) {
System.out.println("present!");
UserDB userDB2 = userDB.get();
System.out.println(userDB2.getPassword());
// The line above prints a valid BCrypt password with 60 characters
user = new User(userDB2.getUsername(), userDB2.getPassword());
}
return user;
}
}
这将更改从保存到存储库的密码
$2a$10$TEU8lkr/aVzJMgtu78.NceUzy8zJG5FCqHcOgNK61AL5or0McLpTq
到
但是我得到了一种新的错误
java.lang.IllegalArgumentException:没有为id“null”映射的PasswordEncoder
给我编码器的新定义的用户将我链接到,有人也有同样的问题。这就是我用我的方式来表达这个问题的原因
这里接受的答案,以及其他一些答案,似乎要么使用Oauth2(一个答案使用我甚至无法导入的类ClientDetailsServiceConfigurer
),禁用加密(或者更确切地说使用一个不做任何事情的编码器),要么使用InMemoryAuthentication而不是数据库。所有这些对我都没有用处,因为我想真正使用它并永久存储我的用户
在当前版本的Spring Security中是否存在某种问题阻止了它的工作?在我看来,唯一缺少的步骤是比较加密密码和登录输入。它在使用inMemoryAuth之前运行良好,没有加密
或者我必须使用一些额外的服务,比如OAuth2(我认为这是对Spring安全性的补充,而不是要求)?我只是想知道什么是有效的,然后我再花三天时间尝试不同的教程,让它看起来应该很容易,然后结果它不知怎么地根本不起作用
我将向您展示我的代码的所有其他相关部分,也许我只是犯了一些非常简单的错误:
首先是WebSecurityConfig
package com.example.demo;
import...
@Configuration
@ComponentScan(basePackages = { "com.example.demo" })
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/main", "/register").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
private MyUserDetailsService userDetailsService;
@Bean(name = "passwordEncoder")
@Qualifier("passwordEncoder")
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
}
注册的控制器:
@PostMapping("/register")
public String workRegistrationForm(Model model, @ModelAttribute("user") UserDto newUser) {
System.out.println(newUser.getUsername() + ", " + newUser.getEmail());
String encodedPW = encoder.encode(newUser.getPassword());
UserDB newUserDB = new UserDB(newUser.getUsername(), encodedPW);
userRepository.save(newUserDB);
return "redirect:/main";
}
添加登录视图的MVC配置:
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/securedtwo").setViewName("securedtwo");
registry.addViewController("/login").setViewName("login");
}
}
login.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
Spring安全示例
无效的用户名和密码。
您已注销。
用户名:
密码:
实现UserDetails的用户(UserDB在没有权限的情况下基本相同):
public类用户实现UserDetails{
字符串密码;
字符串用户名;
公共用户(字符串密码、字符串用户名){
this.password=密码;
this.username=用户名;
}
@凌驾
公共集合您的数据库中似乎有bcrypt
密码未标记为bcrypt
。请尝试:
公共密码编码器PasswordEncoder(){
DelegatingPasswordEncoder编码器=
PasswordEncoderFactorys.createDelegatingPasswordEncoder();
setDefaultPasswordEncoderForMatches(新的BCryptPasswordEncoder());
返回编码器;
}
这应该将没有“{id}”的任何密码解释为bcrypt
[更新。]
由.my code驱动的另一个更改是将方法添加到WebSecurityConfigureAdapter
实现中:
公共类WebSecurityConfigureImpl扩展了WebSecurityConfigureAdapter{
...
@自动连线专用用户详细信息服务用户详细信息服务;
@自动连线专用密码编码器;
@凌驾
public void configure(AuthenticationManagerBuilder auth)引发异常{
auth.userDetailsService(userDetailsService)
.密码编码器(passwordEncoder);
}
...
}
希望这能有所帮助。很遗憾,这不起作用,我得到了错误“密码看起来不像Bcrypt”再一次。你知道我的错误发生在流程的哪一部分吗?是登录密码看起来不像Bcrypt,还是数据库中的密码?错误消息对我没有什么帮助。有一些奇怪的事情发生了,我想知道密码比较问题是否有误导性。在再次查看你的代码后,t我看到的另一个问题是您的userdetails服务。如果找不到用户,loadUserByUsername(String)
需要抛出UsernameNotFoundException
(而不是只返回null
)。我建议添加该代码以查看上游是否发现问题
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/securedtwo").setViewName("securedtwo");
registry.addViewController("/login").setViewName("login");
}
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
public class User implements UserDetails {
String password;
String username;
public User(String password, String username) {
this.password = password;
this.username = username;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<GrantedAuthority> rights = new ArrayList<>();
rights.add(new SimpleGrantedAuthority("USER"));
return rights;
}
..Getters and Setters