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服务的完整相关代码。请注意,在当前配置中,客户端应用程序正在以未加密的文本发送值为password
的密码,但是通过SSL连接:
@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 Security Config的相关部分:
@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);
}
}
答案 0 :(得分:3)
每次都不要创建新的PasswordEncoder。由于BCrypt如何处理盐渍,这不会起作用。相反,创建一个PasswordEncoder bean并在需要时自动装配它。
在SecurityConfiguration中添加:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
然后在需要访问它的控制器中,自动装配它:
@Autowired
private PasswordEncoder passwordEncoder;
这应该可以解决你的问题。
答案 1 :(得分:2)
接口PasswordEncoder
具有如下定义的方法。
boolean matches(CharSequence rawPassword,
String encodedPassword)
验证从存储中获取的编码密码是否与编码后提交的原始密码相匹配。如果密码匹配则返回true,否则返回false。存储的密码本身永远不会被解码。
参数:
rawPassword
- 要编码和匹配的原始密码encodedPassword
- 来自存储的编码密码以与返回:
true
如果编码后的原始密码与存储期望传递一个原始密码(JSON有原始密码,或者您可能必须根据编码方式进行解码,将其转换为原始密码)作为第一个参数,编码密码来自DB作为第二个参数参数。