如何配置 REST 服务以使用 Spring 安全性手动检查加密密码



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 具有原始密码,或者您可能必须根据其编码方式进行解码,以将其转换为原始密码(作为第一个参数,编码的密码来自数据库作为第二个参数。

最新更新