1.配置RememberMe
1.1.修改application.properties
## # 记住我 # cas.ticket.tgt.rememberMe.enabled=true cas.ticket.tgt.rememberMe.timeToKillInSeconds=3600
1.2.修改登录界面
<div class="form-group" th:if="${rememberMeAuthenticationEnabled}"><input type="checkbox" name="rememberMe" id="rememberMe" value="true" tabindex="5"/><label for="rememberMe" th:text="#{screen.rememberme.checkbox.title}">Remember Me</label> </div>
1.3.测试流程
第一步:首先 不选择记住我登录 然后退出浏览器。
第二步:打开浏览器,再次访问服务 发现需要登录。
第三步:选择 记住我登录,然后退出浏览器。
第四步:打开浏览器,访问服务,直接就是登录成功状态。(前提是退出浏览器前不要登出)
2.添加验证码
从页面登录页面上我们可以知道,登陆的用户名和密码信息绑定到了credential这个对象上的。
如果开启了RememberMe的功能就使用RememberMeUsernamePasswordCredential。
如果没有就使用UsernamePasswordCredential了,这里我们使用RememberMeUsernamePasswordCredential。
2.1.添加依赖
<dependency><groupId>org.apereo.cas</groupId><artifactId>cas-server-core-authentication</artifactId><version>${cas.version}</version> </dependency> <dependency><groupId>org.apereo.cas</groupId><artifactId>cas-server-core-authentication-api</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>
这里可能会在后续继承DefaultLoginWebflowConfigurer时无法导入依赖
虽然cas-server-core-webflow中有那个类,但是无法导入,所以单独引入cas-server-core-webflow-api这个依赖
2.2.重写credential
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apereo.cas.authentication.RememberMeUsernamePasswordCredential;public class RememberMeUsernamePasswordCaptchaCredential extends RememberMeUsernamePasswordCredential {private String captcha;public String getCaptcha() {return captcha;}public void setCaptcha(String captcha) {this.captcha = captcha;}@Overridepublic int hashCode() {return new HashCodeBuilder().appendSuper(super.hashCode()).append(this.captcha).toHashCode();} }
2.3.新建DefaultCaptchaWebflowConfigurer修改之前默认的Credential
import org.apereo.cas.authentication.UsernamePasswordCredential; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.web.flow.CasWebflowConstants; import org.apereo.cas.web.flow.configurer.DefaultLoginWebflowConfigurer; 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 DefaultCaptchaWebflowConfigurer extends DefaultLoginWebflowConfigurer {public DefaultCaptchaWebflowConfigurer(FlowBuilderServices flowBuilderServices, FlowDefinitionRegistry flowDefinitionRegistry, ApplicationContext applicationContext, CasConfigurationProperties casProperties) {super(flowBuilderServices, flowDefinitionRegistry, applicationContext, casProperties);}@Overrideprotected void createRememberMeAuthnWebflowConfig(Flow flow) {if (casProperties.getTicket().getTgt().getRememberMe().isEnabled()) {createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, RememberMeUsernamePasswordCaptchaCredential.class);final ViewState state = getState(flow, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM, ViewState.class);final BinderConfiguration cfg = getViewStateBinderConfiguration(state);cfg.addBinding(new BinderConfiguration.Binding("rememberMe", null, false));cfg.addBinding(new BinderConfiguration.Binding("captcha", null, true));} else {createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, UsernamePasswordCredential.class);final ViewState state = getState(flow, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM, ViewState.class);final BinderConfiguration cfg = this.getViewStateBinderConfiguration(state);cfg.addBinding(new BinderConfiguration.Binding("captcha", null, true));}} }
2.4.创建表单处理器
import com.fdzang.cas.service.framework.ApiResult; import com.fdzang.cas.service.service.UserService; import com.fdzang.cas.service.util.Constant; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult; import org.apereo.cas.authentication.Credential; import org.apereo.cas.authentication.PreventedException; import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler; import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.services.RegisteredService; import org.apereo.cas.services.ServicesManager; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;import javax.security.auth.login.FailedLoginException; import javax.servlet.http.HttpServletRequest; import java.security.GeneralSecurityException;@Slf4j public class RememberMeUsernamePasswordCaptchaAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler {private UserService userService;public RememberMeUsernamePasswordCaptchaAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {super(name, servicesManager, principalFactory, order);}@Overrideprotected AuthenticationHandlerExecutionResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();RememberMeUsernamePasswordCaptchaCredential captchaCredential = (RememberMeUsernamePasswordCaptchaCredential) credential;String requestCaptcha = captchaCredential.getCaptcha();String username = captchaCredential.getUsername();String password = captchaCredential.getPassword();// 校验验证码Object attribute = request.getSession().getAttribute(Constant.CAPTCHA_SESSION_KEY);String realCaptcha = attribute == null ? null : attribute.toString();if(StringUtils.isBlank(requestCaptcha) || !requestCaptcha.equalsIgnoreCase(realCaptcha)){throw new FailedLoginException("验证码错误");}// 获取请求来源URLString referer = request.getHeader("referer");if(referer.indexOf("service=")>0){referer = referer.substring(referer.indexOf("service=")+8);referer.replace("%3A",":");referer.replace("%2F","/");}RegisteredService service = findByServiceId(referer);if (service != null){throw new FailedLoginException("未查询到Service错误");}String appCode = service.getName();// 登录校验ApiResult result = userService.userLogin(username,password,appCode);if(!result.getCode().equals(0L)){throw new FailedLoginException(result.getMsg());}return createHandlerResult(credential, this.principalFactory.createPrincipal(username));}@Overridepublic boolean supports(Credential credential) {return credential instanceof RememberMeUsernamePasswordCaptchaCredential;}public RegisteredService findByServiceId(String serviceId){RegisteredService service = null;try {service = servicesManager.findServiceBy(serviceId);} catch (Exception e) {log.error(e.getMessage());}return service;}public void setUserService(UserService userService) {this.userService = userService;} }
这里我根据自己的需求做了特定的登录校验,仅做参考。
2.5.配置DefaultCaptchaWebflowConfigurer
import com.fdzang.cas.service.captcha.DefaultCaptchaWebflowConfigurer; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.web.flow.CasWebflowConfigurer; 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.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("captchaWebflowConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) @AutoConfigureBefore(value = CasWebflowContextConfiguration.class) public class CaptchaWebflowConfiguration {@Autowired@Qualifier("loginFlowRegistry")private FlowDefinitionRegistry loginFlowRegistry;@Autowiredprivate ApplicationContext applicationContext;@Autowiredprivate CasConfigurationProperties casProperties;@Autowired@Qualifier("builder")private FlowBuilderServices builder;@Bean("defaultLoginWebflowConfigurer")public CasWebflowConfigurer defaultLoginWebflowConfigurer() {DefaultCaptchaWebflowConfigurer c = new DefaultCaptchaWebflowConfigurer(builder, loginFlowRegistry, applicationContext, casProperties);c.initialize();return c;} }
2.6.配置表单处理器
import com.fdzang.cas.service.captcha.RememberMeUsernamePasswordCaptchaAuthenticationHandler; import com.fdzang.cas.service.service.UserService; import org.apereo.cas.authentication.AuthenticationEventExecutionPlan; import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer; import org.apereo.cas.authentication.AuthenticationHandler; import org.apereo.cas.authentication.principal.DefaultPrincipalFactory; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.services.ServicesManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration("rememberMeConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class RememberMeCaptchaConfiguration implements AuthenticationEventExecutionPlanConfigurer {@Autowired@Qualifier("servicesManager")private ServicesManager servicesManager;@Autowiredprivate UserService userService;@Beanpublic AuthenticationHandler rememberMeUsernamePasswordCaptchaAuthenticationHandler() {RememberMeUsernamePasswordCaptchaAuthenticationHandler handler = new RememberMeUsernamePasswordCaptchaAuthenticationHandler(RememberMeUsernamePasswordCaptchaAuthenticationHandler.class.getSimpleName(),servicesManager,new DefaultPrincipalFactory(),9);handler.setUserService(userService);return handler;}@Overridepublic void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {plan.registerAuthenticationHandler(rememberMeUsernamePasswordCaptchaAuthenticationHandler());} }
2.7.加载配置类,spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.apereo.cas.config.CasEmbeddedContainerTomcatConfiguration,\org.apereo.cas.config.CasEmbeddedContainerTomcatFiltersConfiguration,\com.fdzang.cas.service.config.SpringConfig,\com.fdzang.cas.service.config.RememberMeCaptchaConfiguration,\com.fdzang.cas.service.config.CaptchaWebflowConfiguration
2.8.验证码生成工具类
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.9.验证码控制层
import com.fdzang.cas.service.util.CaptchaUtil; import com.fdzang.cas.service.util.Constant; 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(Constant.CAPTCHA_SESSION_KEY);session.setAttribute(Constant.CAPTCHA_SESSION_KEY, code.toString());// 将内存中的图片通过流动形式输出到客户端ImageIO.write(image, "JPEG", response.getOutputStream());} catch (Exception e) {e.printStackTrace();}} }
2.10.修改登录页面
<div class="form-group"><label for="captcha">验证码:</label><input class="required" id="captcha" name="captcha" size="10"tabindex="2" th:field="*{captcha}" autocomplete="off"/><img th:src="@{/captcha.jpg}" id="captcha_img" onclick="javascript:refreshCaptcha()"/> </div><script type="text/javascript">function refreshCaptcha(){$("#captcha_img").attr("src","/cas/captcha.jpg?id=" + new Date() + Math.floor(Math.random()*24));} </script>
2.11.注释默认登录逻辑
#cas.authn.accept.users=admin::123456
参考:https://blog.csdn.net/qq_34021712/article/details/82259101