首页 文章

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

提问于
浏览
0

RESTful Spring Boot服务需要手动登录其凭据通过JSON从AngularJS前端发送的用户 . 下面的代码使用未加密的密码来完成此操作,但我希望密码在存储在数据库中时加密 . 当我将 BCryptPasswordEncoder().matches... 添加到下面的代码时,它仍然无法匹配加密的用户密码 . What specific changes need to be made to the code below so that the /login1 method is able to perform manual password checking and thus then be able to perform its custom login procedures?

以下是登录过程中当前未能进行密码匹配的四行,但失败的原因可能是密码在注册过程中的加密方式:

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 回答

  • 2

    接口 PasswordEncoder 具有如下定义的方法 .

    boolean matches(CharSequence rawPassword,
              String encodedPassword)
    

    验证从存储中获取的编码密码是否与编码后提交的原始密码相匹配 . 如果密码匹配则返回true,否则返回false . 存储的密码本身永远不会被解码 .

    参数:

    • rawPassword - 要编码和匹配的原始密码

    • encodedPassword - 来自存储的编码密码与之比较

    返回:

    • true 如果编码后的原始密码与存储中的编码密码匹配

    它期望传递一个原始密码(或者JSON有原始密码,或者您可能必须根据它的编码方式进行解码,将其转换为原始密码)作为第一个参数,编码密码来自DB作为第二个参数 .

  • 3

    不要每次都创建一个新的PasswordEncoder . 由于BCrypt如何处理盐析,这是行不通的 . 相反,创建一个PasswordEncoder bean并在需要时自动装配它 .

    在SecurityConfiguration中添加以下内容:

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    

    然后在需要访问它的控制器中,自动装配它:

    @Autowired 
    private PasswordEncoder passwordEncoder;
    

    那应该可以解决你的问题 .

相关问题