RESTful Spring Boot 服务需要手动登录用户,这些用户的凭据是通过 JSON 从 AngularJS 前端发送的。 下面的代码使用未加密的密码完成此操作,但我希望密码在存储在数据库中时对其进行加密。 当我在下面的代码中添加BCryptPasswordEncoder().matches...
时,它仍然无法匹配加密的用户密码。 需要对下面的代码进行哪些具体更改,以便/login1
方法能够执行手动密码检查,从而能够执行其自定义登录过程?
以下是登录过程中当前无法进行密码匹配的四行,尽管失败可能是由于注册过程中密码的加密方式:
UserDetails user = users.loadUserByUsername(uname);
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encpwd = encoder.encode(rphon.getEncpwd());//takes JSON unencoded string value `password` and encodes it using encoder.encode(...)
if(encoder.matches(user.getPassword(), encpwd)){//this encoder.matches check fails
以下是 Spring Boot 应用程序中两个 REST 服务的完整相关代码,它们分别处理注册(密码加密(和身份验证(密码匹配(。 请注意,在当前配置中,客户端应用通过 SSL 连接发送值为password
未加密文本的密码:
@RequestMapping(value = "/register", method = RequestMethod.POST)
public @ResponseBody ResultMessage getPin(@RequestBody ResultMessage rmsg) {
String uname = rmsg.getName();
WebLead wld = myrepo.findByEmailaddress(uname);
User newusr = new User();
newusr.setName(wld.getEmailaddress());
PasswordEncoder encoder = new BCryptPasswordEncoder();
String pwd = encoder.encode("password");
newusr.setPassword(pwd);
users.createUser(newusr);
// bunch of unrelated code
return something;
}
@RequestMapping(value = "/login1", method = RequestMethod.POST)
public @ResponseBody ResultMessage login1(HttpSession session, HttpServletResponse response, @RequestBody ResultMessage rphon) {
ResultMessage resmess = new ResultMessage();
String uname = rphon.getName();
resmess.setName(uname);
UserDetails user = users.loadUserByUsername(uname);
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encpwd = encoder.encode(rphon.getEncpwd());//takes JSON unencoded string value `password` and encodes it using encoder.encode(...)
if(encoder.matches(user.getPassword(), encpwd)){
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, auth);
SecurityContextHolder.getContext().setAuthentication(authentication);
response.addCookie(new Cookie("AUTH", "yes"));
}
return resmess;
}
以下是 Spring 安全配置的相关部分:
@SuppressWarnings("deprecation")
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(new MyAuthenticationSuccessHandler())
.and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/register").permitAll()
.antMatchers("/login1").permitAll()
.antMatchers("/index.html", "/", "/gui_route_1", "/gui_route_2", "/gui_route_n").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
}
不要每次都创建新的密码编码器。由于 BCrypt 处理盐渍的方式,这是行不通的。相反,创建一个 PasswordEncoder bean 并在需要时自动连接它。
在安全配置中添加以下内容:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
然后在需要访问它的控制器中,自动连线它:
@Autowired
private PasswordEncoder passwordEncoder;
这应该可以解决你的问题。
接口PasswordEncoder
具有如下定义的方法。
boolean matches(CharSequence rawPassword,
String encodedPassword)
验证从存储中获取的编码密码是否与提交的原始密码匹配。如果密码匹配,则返回 true;如果不匹配,则返回 false。存储的密码本身永远不会被解码。
参数:
-
rawPassword
- 要编码和匹配的原始密码 -
encodedPassword
- 存储中要与之比较的编码密码
返回:
-
true
编码后的原始密码是否与存储中的编码密码匹配
它期望传递一个原始密码(JSON 具有原始密码,或者您可能必须根据其编码方式进行解码,以将其转换为原始密码(作为第一个参数,编码的密码来自数据库作为第二个参数。