展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

用户名 + 密码 + 图形验证认证

  • 修改CustomAuthenticationFailureHandler类和CustomAuthenticationSuccessHandler
# 将实现接口AuthenticationSuccessHandler修改为SavedRequestAwareAuthenticationSuccessHandler 
@Component("customAuthenticationSuccessHandler")
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        System.out.println("CustomAuthenticationSuccessHandler ---> 认证成功");
    }
}

@Component("customAuthenticationFailureHandler")
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        System.out.println("CustomAuthenticationFailureHandler ---> 认证失败");
    }
}
  • 实现图形验证码
# core模块导入依赖
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
</dependency>

# core模块编写配置类KaptchaImageCodeConfig
@Configuration
public class KaptchaImageCodeConfig {
    @Bean
    public DefaultKaptcha getDefaultKaptcha(){
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty(Constants.KAPTCHA_BORDER, "yes");
        properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "192,192,192");
        properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "110");
        properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "36");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "28");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体");
        properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        // 图片效果
        properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

# 编写CustomLoginController获取验证码
@Controller
public class CustomLoginController {
    Logger logger = LoggerFactory.getLogger(getClass());
    public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
    @Autowired
    private DefaultKaptcha defaultKaptcha;
    // 获取图形验证码
    @RequestMapping("/code/image")
    public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 1. 获取验证码字符串
        String code = defaultKaptcha.createText();
        logger.info("生成的图形验证码是:" + code);
        // 2. 字符串把它放到session中
        request.getSession().setAttribute(SESSION_KEY , code);
        // 3. 获取验证码图片
        BufferedImage image = defaultKaptcha.createImage(code);
        // 4. 将验证码图片把它写出去
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
    }
}

# 前端获取发送请求获取
GET http://localhost:8080/code/image HTTP/1.1

# core模块的SpringSecurityConfig中放行获取图形验证码的接口
  • 自定义验证码过滤器
# code模块编写ImageCodeValidateFilter、ValidateCodeException
@Component("imageCodeValidateFilter")
public class ImageCodeValidateFilter extends OncePerRequestFilter {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
          HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String sessionCode =
                (String)request.getSession().getAttribute(CustomLoginController.SESSION_KEY);
        // 获取用户输入的验证码
        String inpuCode = request.getParameter("code");
        logger.info("session中的验证码为:" + sessionCode);
        logger.info("登录时输入的验证码为:" + inpuCode);
        // 认证路径
        String loginUrl = "/login";
        // 1. 如果是post方式 的登录请求,则校验输入的验证码是否正确
        if(loginUrl.equals(request.getRequestURI())
                && request.getMethod().equalsIgnoreCase("post")) {
           try {
               // 校验验证码合法性
               validate(request);
           }catch (AuthenticationException e) {
               // 交给失败处理器进行处理异常
               customAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);
               // 一定要记得结束
               return;
           }
        }
        // 放行请求
        filterChain.doFilter(request, response);
    }

    private void validate(HttpServletRequest request) {
        // 先获取seesion中的验证码
        String sessionCode =
                (String)request.getSession().getAttribute(CustomLoginController.SESSION_KEY);
        // 获取用户输入的验证码
        String inpuCode = request.getParameter("code");
        logger.info("session中的验证码为:" + sessionCode);
        logger.info("登录时输入的验证码为:" + inpuCode);
        // 判断是否正确
        if(StringUtils.isBlank(inpuCode)) {
            throw new ValidateCodeException("验证码不能为空");
        }
        if(!inpuCode.equalsIgnoreCase(sessionCode)) {
            throw new ValidateCodeException("验证码输入错误");
        }
    }

}

# code模块的SpringSecurityConfig中添加如下:注入过滤器,并添加到UsernamePasswordAuthenticationFilter过滤器前
@Autowired
private ImageCodeValidateFilter imageCodeValidateFilter;

.addFilterBefore(imageCodeValidateFilter, UsernamePasswordAuthenticationFilter.class)

# 测试:使用用户名 + 密码 + 图形验证码进行认证
POST http://localhost:8080/login?username=admin&password=admin&code=b2bf HTTP/1.1
posted @ 2022-06-24 06:47  DogLeftover  阅读(32)  评论(0编辑  收藏  举报