Adding a verification code to login is a very common requirement, and there are well established solutions online. Adding a login verification code to the traditional login process is not difficult, but adding a login verification code to Spring Security can be quite challenging for beginners because by default we do not need to write our own login authentication logic. You only need to configure it a little yourself, so adding a login verification code involves adding your own authentication logic to Spring Security’s existing authentication system.

If you are not familiar with the operation of Spring Security, you can reply to springBoot in the background of the public account. Get Songo Pure hand knock 274 free Spring Boot learning dry goods.

Ok, so next, let’s look at how I added the login verification code to the micro person through the custom filter.

[Link to hand-hold video tutorial]

Ok, I don’t know if you guys understand this? All the code covered in the video has been submitted to GitHub: github.com/lenve/vhr. If you are interested in the complete micro personnel video tutorial, you can click here :Spring Boot + Vue

Finally, there is a note on the verification code written last year, friends can also refer to.

Preparing the verification code

To have a verification code, you must first prepare the verification code, this paper uses Java self-drawn verification code, the code is as follows:

/** * Utility class for generating captcha */
public class VerifyCode {

	private int width = 100;// Generate the width of the captcha image
	private int height = 50;// Generate the height of the captcha image
	private String[] fontNames = { "宋体"."Regular script"."The official script".Microsoft Yahei };
	private Color bgColor = new Color(255.255.255);// Define the background color of the captcha image as white
	private Random random = new Random();
	private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	private String text;// Record random strings

	/** * gets an arbitrary color **@return* /
	private Color randomColor(a) {
		int red = random.nextInt(150);
		int green = random.nextInt(150);
		int blue = random.nextInt(150);
		return new Color(red, green, blue);
	}

	/** * get a random font **@return* /
	private Font randomFont(a) {
		String name = fontNames[random.nextInt(fontNames.length)];
		int style = random.nextInt(4);
		int size = random.nextInt(5) + 24;
		return new Font(name, style, size);
	}

	/** * gets a random character **@return* /
	private char randomChar(a) {
		return codes.charAt(random.nextInt(codes.length()));
	}

	/** * Create a blank BufferedImage object **@return* /
	private BufferedImage createImage(a) {
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g2 = (Graphics2D) image.getGraphics();
		g2.setColor(bgColor);// Set the background color of the captcha image
		g2.fillRect(0.0, width, height);
		return image;
	}

	public BufferedImage getImage(a) {
		BufferedImage image = createImage();
		Graphics2D g2 = (Graphics2D) image.getGraphics();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 4; i++) {
			String s = randomChar() + "";
			sb.append(s);
			g2.setColor(randomColor());
			g2.setFont(randomFont());
			float x = i * width * 1.0 f / 4;
			g2.drawString(s, x, height - 15);
		}
		this.text = sb.toString();
		drawLine(image);
		return image;
	}

	/** * draw interference line **@param image
	 */
	private void drawLine(BufferedImage image) {
		Graphics2D g2 = (Graphics2D) image.getGraphics();
		int num = 5;
		for (int i = 0; i < num; i++) {
			int x1 = random.nextInt(width);
			int y1 = random.nextInt(height);
			int x2 = random.nextInt(width);
			int y2 = random.nextInt(height);
			g2.setColor(randomColor());
			g2.setStroke(new BasicStroke(1.5 f)); g2.drawLine(x1, y1, x2, y2); }}public String getText(a) {
		return text;
	}

	public static void output(BufferedImage image, OutputStream out) throws IOException {
		ImageIO.write(image, "JPEG", out); }}Copy the code

This tool class is very common and there are many online. It is to draw a simple verification code and write the verification code to the front page through the stream. The Controller that provides the verification code is as follows:

@RestController
public class VerifyCodeController {
    @GetMapping("/vercode")
    public void code(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        VerifyCode vc = new VerifyCode();
        BufferedImage image = vc.getImage();
        String text = vc.getText();
        HttpSession session = req.getSession();
        session.setAttribute("index_code", text); VerifyCode.output(image, resp.getOutputStream()); }}Copy the code

Create a VerifyCode object, save the generated captcha character to session, and stream the image to the front end. The img tag looks like this:

<img src="/vercode" alt="">
Copy the code

The display effect is as follows:

Custom filter

I don’t need to say more about displaying captcha on the landing page. Let’s see how to customize the captcha handler:

@Component
public class VerifyCodeFilter extends GenericFilterBean {
    private String defaultFilterProcessUrl = "/doLogin";

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if ("POST".equalsIgnoreCase(request.getMethod()) && defaultFilterProcessUrl.equals(request.getServletPath())) {
            // Verification code verification
            String requestCaptcha = request.getParameter("code");
            String genCaptcha = (String) request.getSession().getAttribute("index_code");
            if (StringUtils.isEmpty(requestCaptcha))
                throw new AuthenticationServiceException("The captcha cannot be empty!");
            if(! genCaptcha.toLowerCase().equals(requestCaptcha.toLowerCase())) {throw new AuthenticationServiceException("Verification code error!"); } } chain.doFilter(request, response); }}Copy the code

The custom filter inherits from GenericFilterBean and implements the doFilter method. In the doFilter method, when the request method is POST and the request address is /doLogin, the value of the code field in the parameter is obtained. This field saves the verification code sent by the user from the front page, and then obtains the verification code saved in the session. If the user does not send the verification code, the verification code cannot be a null exception is thrown. If the user sends the verification code, it determines whether the verification code is correct. Otherwise, run chain.doFilter(request, response). Make the request continue down.

configuration

Finally, in the Spring Security configuration, configure the filter as follows:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @AutowiredVerifyCodeFilter verifyCodeFilter; . .@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")... . .permitAll() .and() .csrf().disable(); }}Copy the code

Here posted only a part of the core code, namely HTTP, addFilterBefore (verifyCodeFilter, UsernamePasswordAuthenticationFilter. Class); After that, the configuration is complete.

If the verification code is passed incorrectly or not, an exception will be thrown. For example, if the verification code is not passed, the following exception will be thrown:

This article, I have uploaded to GitHub, welcome everyone star: github.com/lenve/javab…

Well, this article first said here, have a question welcome comment discussion.