CAS单点登录-自定义认证之重写Credential(十五)
来源:互联网 发布:php ajax返回json数据 编辑:程序博客网 时间:2024/06/13 01:27
CAS单点登录-自定义认证之重写Credential (十五)
ps:这一章拖了非常久,最近事情也比较多,希望能谅解~
再次目前使用cas版本为:5.1.5
我们使用sso的时候往往登录不只是需要用户名密码,更多的是有时候选择部门,系统等等的扩展校验信息,当然有时候还有校验码策略,例如同一个IP10分钟内输入密码错误3次输入验证码等等的业务场景~
那么这一章讲一下如何扩展校验信息以及自定义校验器。
需求
- 登录新增校验信息
- 自定义校验模式
业务场景:
1. 登录页新增系统下拉框选择,当是SSO时,匹配自定义校验器
2. 自定义校验器,当系统未sso并且用户名为admin时,允许认证成功
本章目的,自定义Credential以及自定义
AuthenticationHandler
铺垫
所需知识:
1. 对cas有所了解
2. 对自定义AuthenticationHandler有所了解
3. 对cas的credential
有所了解
4. 对spring webflow有基础了解
5. spring boot的使用经验
若不具备以上知识或许看以下的内容有所吃力。
实战
介绍
流程:
- 重新指定
CasWebflowConstants.VAR_ID_CREDENTIAL
- 对登录页的flow
CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM
重写绑定参数 - 登录页锁定参数
- 自定义
AuthenticationHandler
- 采用
spring.factories
注册
程序
UsernamePasswordSysCredential
该代码定义前端所需定义的绑定参数,后续会交给AuthenticationHandler进行认证
为了测试简单,也不影响其他鉴权模式,所以直接继承RememberMeUsernamePasswordCredential,再日常的开发慎重考虑这个bean的设计
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.sso.support.auth;import org.apache.commons.lang3.builder.HashCodeBuilder;import org.apereo.cas.authentication.RememberMeUsernamePasswordCredential;import javax.validation.constraints.Size;/** * 用户名,密码,系统 * * @author Carl * @date 2017/10/23 * @since */public class UsernamePasswordSysCredential extends RememberMeUsernamePasswordCredential { @Size(min = 2, message = "require system") private String system; public String getSystem() { return system; } public UsernamePasswordSysCredential setSystem(String system) { this.system = system; return this; } @Override public int hashCode() { return new HashCodeBuilder() .appendSuper(super.hashCode()) .append(this.system) .toHashCode(); }}
绑定参数
前端重写绑定参数,并且重写指定原有的“
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.sso.support.auth;import org.apereo.cas.web.flow.AbstractCasWebflowConfigurer;import org.apereo.cas.web.flow.CasWebflowConstants;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;/** * 重新定义默认的web流程 * * @author Carl * @date 2017/10/23 * @since 1.6.0 */public class CustomWebflowConfigurer extends AbstractCasWebflowConfigurer { public CustomWebflowConfigurer(FlowBuilderServices flowBuilderServices, FlowDefinitionRegistry flowDefinitionRegistry) { super(flowBuilderServices, flowDefinitionRegistry); } @Override protected void doInitialize() throws Exception { final Flow flow = getLoginFlow(); bindCredential(flow); } /** * 绑定输入信息 * * @param flow */ protected void bindCredential(Flow flow) { //重写绑定自定义credential createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, UsernamePasswordSysCredential.class); //登录页绑定新参数 final ViewState state = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM); final BinderConfiguration cfg = getViewStateBinderConfiguration(state); //由于用户名以及密码已经绑定,所以只需对新加系统参数绑定即可 cfg.addBinding(new BinderConfiguration.Binding("system", null, false)); }}
UsernamePasswordSystemAuthenticationHandler
当用户名为admin,并且system为sso即允许通过为了测试简单才定义简单的逻辑,开发过程中慎重考虑
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.sso.support.auth.handler;import com.carl.sso.support.auth.UsernamePasswordSysCredential;import org.apereo.cas.authentication.Credential;import org.apereo.cas.authentication.HandlerResult;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.ServicesManager;import javax.security.auth.login.AccountNotFoundException;import java.security.GeneralSecurityException;import java.util.Collections;/** * 用户名系统认证,只要是admin用户加上sso系统就允许通过 * * @author Carl * @date 2017/10/23 * @since 1.6.0 */public class UsernamePasswordSystemAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler { public UsernamePasswordSystemAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) { super(name, servicesManager, principalFactory, order); } @Override protected HandlerResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException { //当用户名为admin,并且system为sso即允许通过 UsernamePasswordSysCredential sysCredential = (UsernamePasswordSysCredential) credential; if ("admin".equals(sysCredential.getUsername()) && "sso".equals(sysCredential.getSystem())) { //这里可以自定义属性数据 return createHandlerResult(credential, this.principalFactory.createPrincipal(((UsernamePasswordSysCredential) credential).getUsername(), Collections.emptyMap()), null); } else { throw new AccountNotFoundException("必须是admin用户才允许通过"); } } @Override public boolean supports(Credential credential) { return credential instanceof UsernamePasswordSysCredential; }}
注册CasWebflowConfigurer
这里是spring boot的知识,需要对配置进行识别
由于需要对Credential进行重写定义,必须在该配置之前注册,否则自定义的无法重写
@AutoConfigureBefore(value = CasWebflowContextConfiguration.class)
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.sso.support.auth.config;import com.carl.sso.support.auth.CustomWebflowConfigurer;import org.apereo.cas.config.CasWebflowContextConfiguration;import org.apereo.cas.configuration.CasConfigurationProperties;import org.apereo.cas.web.flow.CasWebflowConfigurer;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.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;import org.springframework.webflow.engine.builder.support.FlowBuilderServices;/** * @author Carl * @date 2017/10/23 * @since 1.6.0 */@Configuration("customerAuthWebflowConfiguration")@EnableConfigurationProperties(CasConfigurationProperties.class)@AutoConfigureBefore(value = CasWebflowContextConfiguration.class)public class CustomerAuthWebflowConfiguration { @Autowired @Qualifier("logoutFlowRegistry") private FlowDefinitionRegistry logoutFlowRegistry; @Autowired @Qualifier("loginFlowRegistry") private FlowDefinitionRegistry loginFlowRegistry; @Autowired @Qualifier("builder") private FlowBuilderServices builder; @Bean public CasWebflowConfigurer customWebflowConfigurer() { final CustomWebflowConfigurer c = new CustomWebflowConfigurer(builder, loginFlowRegistry); c.setLogoutFlowDefinitionRegistry(logoutFlowRegistry); return c; }}
注册AuthenticationHandler
/* * 版权所有.(c)2008-2017. 卡尔科技工作室 */package com.carl.sso.support.auth.config;import com.carl.sso.support.auth.handler.UsernamePasswordSystemAuthenticationHandler;import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;import org.apereo.cas.authentication.AuthenticationHandler;import org.apereo.cas.authentication.principal.PrincipalFactory;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;/** * @author Carl * @date 2017/10/23 * @since 1.6.0 */@Configuration("customAuthenticationEventExecutionPlanConfiguration")@EnableConfigurationProperties(CasConfigurationProperties.class)public class CustomAuthenticationEventExecutionPlanConfiguration implements AuthenticationEventExecutionPlanConfigurer { @Autowired @Qualifier("servicesManager") private ServicesManager servicesManager; @Autowired @Qualifier("jdbcPrincipalFactory") public PrincipalFactory jdbcPrincipalFactory; /** * 注册验证器 * * @return */ @Bean public AuthenticationHandler customAuthenticationHandler() { //优先验证 return new UsernamePasswordSystemAuthenticationHandler("customAuthenticationHandler", servicesManager, jdbcPrincipalFactory, 1); } //注册自定义认证器 @Override public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) { plan.registerAuthenticationHandler(customAuthenticationHandler()); }}
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.carl.sso.support.auth.config.CustomerAuthWebflowConfiguration,com.carl.sso.support.auth.config.CustomAuthenticationEventExecutionPlanConfiguration
casLoginView.html
新加绑定系统信息
<!DOCTYPE html><!-- ~ 版权所有.(c)2008-2017.卡尔科技工作室 --><html><head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <title th:text="${#themes.code('demo.pageTitle')}"></title> <link rel="stylesheet" th:href="@{${#themes.code('demo.css.file')}}"/></head><body><h1 th:text="${#themes.code('demo.pageTitle')}"></h1><div> <form method="post" th:object="${credential}"> <div th:if="${#fields.hasErrors('*')}"> <span th:each="err : ${#fields.errors('*')}" th:utext="${err}"/> </div> <h2 th:utext="#{screen.welcome.instructions}"></h2> <section class="row"> <label for="username" th:utext="#{screen.welcome.label.netid}"/> <div th:unless="${openIdLocalId}"> <input class="required" id="username" size="25" tabindex="1" type="text" th:disabled="${guaEnabled}" th:field="*{username}" th:accesskey="#{screen.welcome.label.netid.accesskey}" autocomplete="off"/> </div> </section> <section class="row"> <label for="password" th:utext="#{screen.welcome.label.password}"/> <div> <input class="required" type="password" id="password" size="25" tabindex="2" th:accesskey="#{screen.welcome.label.password.accesskey}" th:field="*{password}" autocomplete="off"/> </div> </section> <section class="row"> <label for="system" >系统</label> <div> <select class="required" id="system" tabindex="2" th:accesskey="#{screen.welcome.label.password.accesskey}" th:field="*{system}" autocomplete="off"> <option value="sso">SSO</option> <option value="oa">OA</option> <option value="crm">CRM</option> </select> </div> </section> <section> <input type="hidden" name="execution" th:value="${flowExecutionKey}"/> <input type="hidden" name="_eventId" value="submit"/> <input type="hidden" name="geolocation"/> <input class="btn btn-submit btn-block" name="submit" accesskey="l" th:value="#{screen.welcome.button.login}" tabindex="6" type="submit"/> </section> </form></div></body></html>
重点为以下代码
<section class="row"> <label for="system" >系统</label> <div> <select class="required" id="system" tabindex="2" th:accesskey="#{screen.welcome.label.password.accesskey}" th:field="*{system}" autocomplete="off"> <option value="sso">SSO</option> <option value="oa">OA</option> <option value="crm">CRM</option> </select> </div> </section>
测试
- 由于配置了主题,demo主题在触发到demo主题下才会进入以上节目
- 由于继承了RememberMeUsernamePasswordCredential所以其他配置该credential依然生效
- 由于自定义
UsernamePasswordSystemAuthenticationHandler
的认证循序放在第一,所以优先验证
注意事项
- 优先绑定
Credential
@AutoConfigureBefore(value = CasWebflowContextConfiguration.class) - 页面绑定新参数
th:field="*{system}"
- 采用spring.factories注册
- flow绑定新参数
CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM
下载代码尝试: 其他版本可以到GitHub或者码云查看
发现一些意外的事情可以考虑翻翻前面的博客进行学习哦
作者联系方式
如果技术的交流或者疑问可以联系或者提出issue。
邮箱:huang.wenbin@foxmail.com
QQ: 756884434 (请注明:SSO-CSDN)
- CAS单点登录-自定义认证之重写Credential(十五)
- CAS单点登录-自定义认证之JDBC(五)
- CAS单点登录-自定义认证之Shiro、Rest(六)
- Cas之5.2.x版本单点登录自定义REST认证-yellowcong
- CAS 实现单点登录(SSO)数据库查询认证机制-自定义编码方式(四)
- 利用CAS之SSO模块实现单点登录认证
- CAS单点登录源码解析之【用户认证】
- 4、CAS单点登录源码解析之【用户认证】
- SSO之CAS+LDAP实现单点登录认证
- 基于CAS实现单点登录(SSO):CAS+LDAP实现单点登录认证
- CAS单点登录服务器端验证重写
- sso单点登录,cas统一认证
- jasig CAS实现单点登录(数据库认证)
- jasig CAS实现单点登录(数据库认证)
- jasig CAS实现单点登录(数据库认证)
- CAS单点登录-配置数据库认证方式
- CAS 介绍 单点登录认证系统
- CAS+LDAP实现单点登录认证
- ORB 优化(5)
- 每天一个linux命令(22):find 命令的参数详解
- 八段代码彻底掌握Promise
- C的栈、堆、自由存储区(C++)、全局/静态存储区、常量存储区
- ORB-SLAM(六)回环检测
- CAS单点登录-自定义认证之重写Credential(十五)
- Error: 源值1.5已过时-source 1.5 中不支持 lambda 表达式 (请使用 -source 8 或更高版本以启用 lambda 表达式)
- 原生JS实现AJAX、JSONP及DOM加载完成事件
- Springmvc下实现多个图片文件的上传与保存
- simple.data查询返回单属性、单列表结果标量值(变量)
- 图解WebGL&Three.js工作原理
- self 同类分布 (数位dp)
- 连续子段的差异
- 安卓是否真的能够将苹果击败?