【SSO单点系列】(7):CAS4.0 SERVER通过数据库方式认证用户
在前几篇中有简单介绍服务端的认证方式,默认的是直接在 deployerConfigContext.xml 文件中 一个叫做 primaryAuthenticationHandler 的bean中配置。不过这只支持一个账号,而且是固定的,这有非常大的局限性,在现实系统中是肯定不能用这样的方式的。
现在的应用系统一般都是通过读取数据库的方式验证用户名、密码是否正确,进而进行认证的。因此在这一篇文章中将会介绍,怎么把服务端的默认认证方式改造成数据库验证的方式,以此满足系统的基本需求。
1.增加数据源配置
数据源的配置和平常我们配置的差不多,CAS可以使用Spring方式进行配置,为了和原来的配置文件分开,我新建了一个叫做 applicationContext-datasource.xml 的配置用来存放数据源的相关配置,(放在cas-server-webapp\src\main\webapp\WEB-INF\spring-configuration下)具体如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<description>datasource</description> <bean id="casDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<property name="driverClassName" value="${driverClassName}" /> <property name="maxActive" value="${maxActive}" />
<property name="initialSize" value="${initialSize}" />
<property name="maxWait" value="${maxWait}" />
<property name="minIdle" value="${minIdle}" /> <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> <property name="validationQuery" value="${validationQuery}" />
<property name="testWhileIdle" value="${testWhileIdle}" />
<property name="testOnBorrow" value="${testOnBorrow}" />
<property name="testOnReturn" value="${testOnReturn}" />
<property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" />
<property name="removeAbandoned" value="${removeAbandoned}" /> <!-- 打开removeAbandoned功能 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> <!-- 1800秒,也就是30分钟 -->
<property name="logAbandoned" value="${logAbandoned}" /> <!-- 关闭abanded连接时输出错误日志 -->
</bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="casDataSource" /> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="casDataSource" /> <!-- 通过AOP配置提供事务增强,让AccountService下所有Bean的所有方法拥有事务 -->
<aop:config>
<aop:pointcut id="serviceMethod" expression=" execution(* com.blog.cas.account.service.impl..*(..))" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="update*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice> <bean id="accountService" class="com.blog.cas.account.service.impl.AccountServiceImpl" p:accountDao-ref="accountDao" />
<bean id="accountDao" class="com.blog.cas.account.dao.impl.AccountDaoImpl" p:jdbcTemplate-ref="jdbcTemplate" /> </beans>
注:在这边有定义一个Service、一个Dao ,是用来与数据库进行交互的,里面大家写自己需要的方法就行了。这边使用的Spring提供的JdbcTemplate 进行查询。这两个类就不贴出来了,大家自由实现
然后数据源的相关信息,我直接放在文件 cas.properties(cas-server-webapp\src\main\webapp\WEB-INF\cas.properties), 在最后增加下面的内容:
##
# Jdbc
url=jdbc:oracle:thin:@192.168.1.101:1521:odsorcl
username=blog
password=blog driverClassName=oracle.jdbc.driver.OracleDriver
validationQuery=SELECT 1 from dual filters=stat
maxActive=20
initialSize=1
maxWait=60000
minIdle=10
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true
用的是oracle数据库。
2.自定义认证Handler类
cas 默认使用的认证类为 org.jasig.cas.authentication.AcceptUsersAuthenticationHandler。我们看看它的源码,发现认证是在一个叫做 authenticateUsernamePasswordInternal 的方法中进行的,其实看方法名大家都能猜出来这个方法是做什么的。然后这个类的父类是AbstractUsernamePasswordAuthenticationHandler ,那么我们也继承这个类,实现authenticateUsernamePasswordInternal方法其实就可以了。
这边还要注意一下,authenticateUsernamePasswordInternal 方法中的参数是一个 UsernamePasswordCredential 类型的参数,里面其实包含了我们在页面上输入的用户相关信息,即用户名和密码。好了知道方法了,那么就动手吧。
public class BlogUsersAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler { private AccountServiceImpl accountService; @Override
protected HandlerResult authenticateUsernamePasswordInternal(
UsernamePasswordCredential credential)
throws GeneralSecurityException, PreventedException { String username = credential.getUsername();
String password = credential.getPassword(); boolean flag = accountService.checkAccount(username, password);
if (!flag) {
throw new FailedLoginException();
}
return createHandlerResult(credential, new SimplePrincipal(username), null);
} //省略get/set 方法 }
这边只是一个简单的验证逻辑,实际上可能会复杂点,比如判断用户的状态、是否禁用等等。
然后修改相关的配置,打开文件 cas-server-webapp\src\main\webapp\WEB-INF\deployerConfigContext.xml 找到 id 为 primaryPrincipalResolver 的bean ,把这个修改成我们新增的类
<!-- <bean id="primaryAuthenticationHandler"
class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
<property name="users">
<map>
<entry key="admin" value="admin"/>
</map>
</property>
</bean> --> <bean id="primaryAuthenticationHandler"
class="org.jasig.cas.authentication.BlogUsersAuthenticationHandler">
<property name="accountService" ref="accountService" />
</bean>
好了,现在已经修改成通过数据库认证的方式了,大家可以试试看。
3.认证流程
看完了上面的,大家可能会觉得有点不理解。为什么只加了一个类,覆盖了其中的方法就完成了认证呢,在这节中介绍下大概的一个认证流程,以及到最终的信息返回给客户端的这样的一个流程。
其中一些内容在第四篇中有介绍了,最好先了解下第四篇 登录后用户信息的返回 相关的内容, 传送门
- 用户登录页输入相关信息,点击submit登陆
- 执行AuthenticationViaFormAction 类中的 submit 方法中
- 在submit方法中 调用 CentralAuthenticationService 类的grantServiceTicket 方法,其中有传入 Credential 类型的参数
- 接着在 grantServiceTicket方法中 调用了 AuthenticationManager类(实际类为PolicyBasedAuthenticationManager)的authenticate 方法
- authenticate方法中又调用了authenticateInternal 方法
- 最终在 authenticateInternal 方法中调用了AuthenticationHandler 的authenticate 的方法 ,authenticate 方法就会调用我们上面自定义的 BlogUsersAuthenticationHandler 方法
- 然后根据我们写的方法返回的相关信息调用 resolvePrincipal 方法,把credential 类型的信息转变为Principal类型的信息,即组装我们需要返回给客户端的一些信息。这个主要是通过 PrincipalResolver 类进行转变得,第四篇中有重点说到,这边就不细讲了。
- 最终成功登陆到客户端
上面的流程只是认证的主要流程,不包含ST的生成、验证等过程。
4.总结
通过数据库认证基本上写完了,不过上面只是简单的演示了下,大家需要根据自己的情况进行修改。
如果上面的内容有错误,欢迎大家指出。也欢迎大家多多留言。大家共同进步。
顺便祝大家情人节快乐,新年快乐。
打完收工...
【SSO单点系列】(7):CAS4.0 SERVER通过数据库方式认证用户的更多相关文章
- 【SSO单点系列】(2):CAS4.0 登录页的个性化定制
上一篇 [SSO单点系列](1):CAS环境的搭建介绍了CAS最简单环境的搭建,以及一个例子用来讲解CAS的一个最基础的用法. 今天主要是介绍如何对CAS登录页进行个性化定制. 一.开始 下图是 ...
- Spring Cloud云架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)
上一篇我根据框架中OAuth2.0的使用总结,画了SSO单点登录之OAuth2.0 登出流程,今天我们看一下根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * ...
- (十一) 整合spring cloud云架构 - SSO单点登录之OAuth2.0登录流程(2)
上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...
- Spring Cloud云架构 - SSO单点登录之OAuth2.0登录流程(2)
上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...
- 【SSO单点系列】(4):CAS4.0 SERVER登录后用户信息的返回
接着上一篇,在上一篇中我们描述了怎么在CAS SERVER登录页上添加验证码,并进行登录.一旦CAS SERVER验证成功后,我们就会跳转到客户端中去.跳转到客户端去后,大家想一想,客户端总要获取用户 ...
- 【SSO单点系列】(1):CAS4.0 环境的搭建
一.概述 今天开始写CAS相关的第一篇文章,这篇文章主要是关于CAS环境的搭配,提供给刚刚接触CAS的一个入门指南,并演示一个CAS的最简单的实例 二.环境要求 博主的环境如下: win8.1 64 ...
- 【SSO单点系列】(3):CAS4.0 登录页验证码的添加
2016.08.23 更新 注意:这个教程只适合4.0版本的,4.1以及以上的版本的已经不试用了, 后面几篇有人提到过 源码网盘链接更新了下 : 链接: http://pan.baidu.com/s/ ...
- 【SSO单点系列】(6):CAS4.0 单点流程序列图(中文版)以及相关术语解释(TGT、ST、PGT、PT、PGTIOU)
CAS 相关的内容好久没写了,可能下周会继续更新一些内容吧. 在上一篇中的单点流程序列图由于是从官网直接下载来的,上面都是英文,可能有的朋友看不懂,因此修改成中文的. PS:只修改了一个,第二个图明天 ...
- 【SSO单点系列】(5):CAS4.0 单点流程序列图
刚过元旦假期,感觉自己好久没写博客了,今天更新一篇,主要是CAS 的一个流程图. ps: 这两张图 是直接从官网上找的,都是简单的英语,我这种英语四级没过都看得懂,大家应该没有压力. 1.CAS 基本 ...
随机推荐
- Python Twisted系列教程2:异步编程初探与reactor模式
作者:dave@http://krondo.com/slow-poetry-and-the-apocalypse/ 译者:杨晓伟(采用意译) 这个系列是从这里开始的,欢迎你再次来到这里来.现在我们可 ...
- TableView被Navigation bar挡住的解决办法
在存在遮挡的ViewController的ViewDidload函数里添加以下两句即可解决 self.edgesForExtendedLayout = UIRectEdge.None self.aut ...
- javascript第四节
闭包: 块级作用域: 私有变量:
- JAVA基础知识总结15(集合容器)
集合框架:用于存储数据的容器. 1:对象封装数据,对象多了也需要存储.集合用于存储对象. 2:对象的个数确定可以使用数组,但是不确定怎么办?可以用集合.因为集合是可变长度的. 集合和数组的区别: 1: ...
- docker swarm && compose 示例
docker swarm 创建docker swarm集群 //master节点操作 docker swarm init --advertise-addr materip //node节点操作 -1x ...
- Opennebula自定义VM 实现方法-Contextualizing Virtual Machines 2.2
from:http://archives.opennebula.org/documentation:archives:rel2.2:cong There are two contextualizati ...
- sql去除重复记录 且保留id最小的 没用
第一步:查询重复记录 SELECT * FROM TableName WHERE RepeatFiled IN ( SELECT RepeatFiled FROM TableName ...
- java面试题 级hr解答 非技术问题 !=!=未看
Java基础 ● 集合类以及集合框架:HashMap与HashTable实现原理,线程安全性,hash冲突及处理算法:ConcurrentHashMap: ● 进程和线程的区别: ● Java的并发. ...
- Java虚拟机学习总结之OutOfMemoryError异常
参考:深入理解java虚拟机一书 开始之前,我们也应当搞清楚连个概念,内存泄漏Memory Leak 内存溢出: 内存泄漏:程序中间动态分配了内存,但是在程序结束时没有释放内存,造成这部分内存不可用. ...
- Servlet中response对象Commit状态的分析
response是服务端对客户端请求的一个响应,其中封装了响应头.状态码.内容(也就是最终要在浏览器上显示的HTML代码或者其他数据格式)等. 服务端在把response提交到客户端之前,会使用一个缓 ...