添加Spring Security后怎样处理密码加盐问题

添加Spring Security后怎样处理密码加盐问题

这里说明一下,本文中所提到的加盐并不是固定写死的一个salt字符串,而是使用UUID随机生成的字符串,每个用户都有一个盐,在注册或添加时插入到数据库中

用户认证的流程如下图:
添加Spring Security后怎样处理密码加盐问题_第1张图片

密码加密和校验一般是在PasswordEncoder的实现类里面进行处理

但是由于salt存储在数据库中,无法获取到,所以这里我们将密码的加密处理转移到UsernamePasswordAuthenticationFilter当中 ,这样在PasswordEncoder当中我们只需要进行密码的校验就可以了
下面是我的UsernamePasswordAuthenticationFilter

/**
 * 针对使用用户名和密码进行身份验证而定制化的一个过滤器
 */
public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;
    private RedisTemplate redisTemplate;  //  拿到的Authentication放到Redis里面,避免每用一次都要查
    private IUserService userService;



    public CustomUsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate, IUserService userService) {
        this.authenticationManager = authenticationManager;
        this.redisTemplate = redisTemplate;
        this.userService = userService;

        // /rbac/user/login
        //指定登录接口以及提交方式
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/rbac/user/login", "POST"));
    }

    /**
     * 获取用户名和密码进行认证,替换原来Controller中/rbac/user/login
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            // UserVO前台以json对象的形式传过来 --- 通过IO流的方式读取
            UserLoginVO userLoginVO = new ObjectMapper().readValue(request.getInputStream(), UserLoginVO.class);
            String username = userLoginVO.getUsername();
            String password = userLoginVO.getPassword();
            User user = userService.selectByUsername(username);
            String salt = user.getSalt();
            String md5Password = PasswordEncryptedUtil.getMD5Password(password, salt);
            userLoginVO.setPassword(md5Password);
            //  封装成UsernamePasswordAuthenticationToken,返回的是没有认证的
            UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(userLoginVO.getUsername(), userLoginVO.getPassword());
            return authenticationManager.authenticate(token);// 传去认证
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }


    /**
     * 认证成功调用
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        CustomUserDetails customUserDetails = (CustomUserDetails) authResult.getPrincipal();
        //  将登陆后的用户信息存入Redis,username作为key
        redisTemplate.opsForHash().put("login",customUserDetails.getUsername(),customUserDetails);
        //根据id和name生成token,返回给客户端
        String token = JwtUtils.createToken(customUserDetails.getUser().getId(), customUserDetails.getUser().getName());
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        JSONResponse.out(response, JSONResult.ok("登陆成功!",map));
    }


    /**
     * 认证失败调用
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        JSONResponse.out(response, JSONResult.error("登陆失败!"));
    }

}

项目详情见码云

你可能感兴趣的:(Java开发出现的错误,spring,java,servlet)