cas默认是使用了用户名密码登录
我们可以在用户名密码登陆的基础上新增验证码登录、短信验证码登录等功能
新增验证码得工具类
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));
}
}
该依赖用于获取管理请求的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>
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文件中配置,新增配置如下
表单新增字段在cas中会比较麻烦,我们要添加验证码验证,那么前端登录表单就要新增一个验证码字段,用来存储前端输入的验证码信息
<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>
这个登录是在用户名密码的基础上新增了一个验证码字段,所以我直接继承了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;
}
}
<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>
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));
}
}
新增配置类
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新增配置类信息