cas基础--添加验证码

Published on with 0 views and 0 comments

一、简介

cas默认是使用了用户名密码登录

我们可以在用户名密码登陆的基础上新增验证码登录、短信验证码登录等功能

二、验证码登录

2.1 验证码工具类

新增验证码得工具类

package org.apereo.cas.custom.util;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class CaptchaUtil {
    // 随机产生的字符串
    private static final String RANDOM_STRS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final String FONT_NAME = "Fixedsys";
    private static final int FONT_SIZE = 18;

    private Random random = new Random();

    private int width = 80;// 图片宽
    private int height = 25;// 图片高
    private int lineNum = 50;// 干扰线数量
    private int strNum = 4;// 随机产生字符数量

    /**
     * 生成随机图片
     */
    public BufferedImage genRandomCodeImage(StringBuffer randomCode) {
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);
        g.setColor(getRandColor(110, 120));
        for (int i = 0; i <= lineNum; i++) {
            drowLine(g);
        }
        // 绘制随机字符
        g.setFont(new Font(FONT_NAME, Font.ROMAN_BASELINE, FONT_SIZE));
        for (int i = 1; i <= strNum; i++) {
            randomCode.append(drowString(g, i));
        }
        g.dispose();
        return image;
    }

    /**
     * 给定范围获得随机颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255){
            fc = 255;
        }
        if (bc > 255){
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    /**
     * 绘制字符串
     */
    private String drowString(Graphics g, int i) {
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
                .nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(RANDOM_STRS.length())));
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13 * i, 16);
        return rand;
    }

    /**
     * 绘制干扰线
     */
    private void drowLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int x0 = random.nextInt(16);
        int y0 = random.nextInt(16);
        g.drawLine(x, y, x + x0, y + y0);
    }

    /**
     * 获取随机的字符
     */
    private String getRandomString(int num) {
        return String.valueOf(RANDOM_STRS.charAt(num));
    }
}

2.2 新增servlet依赖

该依赖用于获取管理请求的session

在pom文件的properties属性中添加

 <javax.servlet.versioin>2.3</javax.servlet.versioin>

添加依赖

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>${javax.servlet.versioin}</version>
            <scope>provided</scope>
        </dependency>

2.3 获取验证码图片的接口

package org.apereo.cas.custom.controller;
import org.apereo.cas.custom.constants.CaptchaConstant;
import org.apereo.cas.custom.util.CaptchaUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;

@RestController
public class CaptchaController{
    @GetMapping("/captcha.jpg")
    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("image/jpeg");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expire", 0);
        try {
            HttpSession session = request.getSession();
            CaptchaUtil tool = new CaptchaUtil();
            StringBuffer code = new StringBuffer();
            BufferedImage image = tool.genRandomCodeImage(code);
            session.removeAttribute(CaptchaConstant.CAPTCHA_SESSION_KEY);
            session.setAttribute(CaptchaConstant.CAPTCHA_SESSION_KEY, code.toString());

            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

该接口添加后tomcat启动是扫描不到这个包得,因为他是在我们自定义的包路径下,需要在spring.factories文件中配置,新增配置如下

image.png

三、登陆表单新增字段

表单新增字段在cas中会比较麻烦,我们要添加验证码验证,那么前端登录表单就要新增一个验证码字段,用来存储前端输入的验证码信息

3.1 前端新增字段

<section class="row">
                    <div>
                        <input
                                style="width: 30%"
                                class="required"
                               type="text"
                               id="captcha"
                               size="10"
                               tabindex="3"
                               placeholder="验证码"
                               th:accesskey="#{screen.welcome.label.password.accesskey}"
                               th:field="*{captcha}"
                               autocomplete="off"/>
                        <img style="width: 30%" th:src="@{/captcha.jpg}" id="captcha_img" onclick="javascript:refreshCaptcha()"/>
                    </div>
                </section>

新增请求cas-server获取验证码图片的js

<script type="text/javascript">
    function refreshCaptcha(){
        $("#captcha_img").attr("src","/cas/captcha.jpg?id=" + new Date() + Math.floor(Math.random()*24));
    }
</script>

3.2 自定义Credential

这个登录是在用户名密码的基础上新增了一个验证码字段,所以我直接继承了UsernamePasswordCredential

package org.apereo.cas.custom.entity;

import org.apereo.cas.authentication.UsernamePasswordCredential;

import java.util.logging.Logger;

public class CustomCredential extends UsernamePasswordCredential {
    private String captcha;
    private static final long serialVersionUID = -4166149641561667276L;
    public CustomCredential() {
    }
    public CustomCredential(String captcha) {
        this.captcha = captcha;
    }

    public String getCaptcha() {
        return captcha;
    }

    public void setCaptcha(String captcha) {
        this.captcha = captcha;
    }
}

3.3 新增依赖

        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-web</artifactId>
            <version>${cas.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-webflow</artifactId>
            <version>${cas.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-webflow-api</artifactId>
            <version>${cas.version}</version>
        </dependency>

3.4 配置webflow

cas使用了webflow我们在前端页面新增了字段,为了后端能够接收到字段,还需要绑定该字段

package org.apereo.cas.custom.config;

import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.custom.entity.CustomCredential;
import org.apereo.cas.web.flow.CasWebflowConstants;
import org.apereo.cas.web.flow.configurer.AbstractCasWebflowConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.engine.builder.BinderConfiguration;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;

public class CustomWebFlowConfigurer extends AbstractCasWebflowConfigurer {

    public CustomWebFlowConfigurer(FlowBuilderServices flowBuilderServices, FlowDefinitionRegistry loginFlowDefinitionRegistry, ApplicationContext applicationContext, CasConfigurationProperties casProperties) {
        super(flowBuilderServices, loginFlowDefinitionRegistry, applicationContext, casProperties);
    }

    @Override
    protected void doInitialize() {
        final Flow flow = getLoginFlow();
        bindCredential(flow);
    }

    private void bindCredential(Flow flow) {
        //重写绑定自定义credential
        createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, CustomCredential.class);
        //登录页绑定新参数
        final ViewState state = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);
        final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
        //由于用户名以及密码已经绑定,所以只需对新加系统参数绑定即可
        cfg.addBinding(new BinderConfiguration.Binding("captcha", null, false));

    }
}

3.5 配置类

新增配置类

package org.apereo.cas.custom.config;

import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.web.flow.CasWebflowConfigurer;
import org.apereo.cas.web.flow.CasWebflowConstants;
import org.apereo.cas.web.flow.CasWebflowExecutionPlan;
import org.apereo.cas.web.flow.CasWebflowExecutionPlanConfigurer;
import org.apereo.cas.web.flow.config.CasWebflowContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;

@Configuration
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomerWebFlowConfiguration implements CasWebflowExecutionPlanConfigurer {
    @Autowired
    private CasConfigurationProperties casProperties;
    @Autowired
    private FlowDefinitionRegistry loginFlowRegistry;
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private FlowBuilderServices flowBuilderServices;

    @ConditionalOnMissingBean(name = "customWebFlowConfigurer")
    @Bean
    public CasWebflowConfigurer customWebFlowConfigurer() {
        final CustomWebFlowConfigurer c =  new CustomWebFlowConfigurer(flowBuilderServices,
                loginFlowRegistry, applicationContext, casProperties);
        c.initialize();
        return c;
    }

    @Override
    public void configureWebflowExecutionPlan(final CasWebflowExecutionPlan plan) {
        plan.registerWebflowConfigurer(customWebFlowConfigurer());
    }
}

spring.factories新增配置类信息

image.png


标题:cas基础--添加验证码
作者:wenyl
地址:http://www.wenyoulong.com/articles/2023/09/18/1695001209038.html