如何配置REST服务以使用Spring Security手动检查加密密码?

时间:2016-02-08 21:13:26

标签: java spring encryption spring-security spring-boot

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);
    }

}

2 个答案:

答案 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作为第二个参数参数。