环境说明:IDEA+JDK7+TOMCAT8 注意不要用JDK8,出现冲突需要更新额外jar包版本(不是教程重点)
一、修改登录验证方案
修改deployerConfigContext.xml primaryAuthenticationHandler有多个实现类:
- org.jasig.cas.authentication.LdapAuthenticationHandler
- org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler
- org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler
- org.jasig.cas.support.spnego.authentication.handler.support.JCIFSSpnegoAuthenticationHandler
- org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler
我们选择自己写一个SaaSAuthenticationHandler 继承org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler
<!--| TODO: Replace this component with one suitable for your enviroment.-->
<!--<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
<property name="users">
<map>
<entry key="casuser" value="Mellon"/>
</map>
</property>
</bean>-->
<!--重写 primaryAuthenticationHandler-->
<bean id="primaryAuthenticationHandler"
class="com.mac.sso.authentication.SaaSAuthenticationHandler"/>
二、代码实现
代码实现包含两个部分:
- 重新AbstractUsernamePasswordAuthenticationHandler
- 实现数据库查询
2.1、SaaSAuthenticationHandler
package com.mac.sso.authentication;
import cn.hutool.crypto.SecureUtil;
import com.mac.sso.bean.UserInfo;
import com.mac.sso.service.UserInfoService;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.UsernamePasswordCredential;
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @author: byy
* @date : 2017年11月23日 下午4:59:32
* @Description:自定义数据库方式认证类
*/
public class SaaSAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
@Autowired
private UserInfoService userInfoService;
protected HandlerResult authenticateUsernamePasswordInternal(UsernamePasswordCredential transformedCredential) throws GeneralSecurityException {
//UsernamePasswordCredential参数包含了前台页面输入的用户信息
String username = transformedCredential.getUsername().
replaceAll(" ", "").toLowerCase();//需要剔除空格,大写转小写
String password = transformedCredential.getPassword();
UserInfo userInfo = userInfoService.findByUsername(username);
System.out.println("userInfo="+userInfo);
//1.用户名是否存在验证
if (userInfo == null) {//用户名错误用此异常
throw new FailedLoginException();
}
//生成MD5密码
String md5password = SecureUtil.md5(password);
//2.验证密码是否正确
if (!md5password.equals(userInfo.getPassword())) {
throw new FailedLoginException();
}
//3.返回登陆成功状态,CAS程序继续运行
return createHandlerResult(transformedCredential, new SimplePrincipal(username), null);
}
}
2.2、UserInfoService
package com.mac.sso.service;
import com.mac.sso.bean.UserInfo;
import com.mac.sso.dao.UserInfoDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserInfoService {
@Autowired
private UserInfoDAO userInfoDAO;
public UserInfo findByUsername(String username){
return userInfoDAO.findByUsername(username);
}
}
2.3、UserInfoDAO
package com.mac.sso.dao;
import com.mac.sso.bean.UserInfo;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
/**
* @see UserInfo
* @author byy
*/
@Repository
public class UserInfoDAO {
private static final Logger log = LoggerFactory.getLogger(UserInfoDAO.class);
public UserInfo findByUsername(String username){
Query queryObject = getSession().createQuery("from UserInfo as u where u.username=:username");
Object u= queryObject.setString("username", username).uniqueResult();
return (UserInfo) u;
}
@Resource
private SessionFactory sessionFactory;
private Session session;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getSession() {
this.session = sessionFactory.getCurrentSession();
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
2.4、UserInfo
package com.mac.sso.bean;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* UserInfo entity. @author MyEclipse Persistence Tools
*/
@Entity
@Table(name = "user_info")
public class UserInfo implements java.io.Serializable {
private static final long serialVersionUID = -8017178229381500057L;
private Integer uid;
private String username;
private String password;
private String realname;
public UserInfo() {
}
public UserInfo(Integer uid, String username, String password, String realname) {
this.uid = uid;
this.username = username;
this.password = password;
this.realname = realname;
}
@Id
@Column(name = "uid", unique = true, nullable = false, length = 50)
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
@Column(name = "username", length = 100)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Column(name = "password", length = 100)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Column(name = "realname", length = 100)
public String getRealname() {
return this.realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
@Override
public String toString() {
return "UserInfo{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", realname='" + realname + '\'' +
'}';
}
}
三、数据库配置
数据库:mysql5.6 连接池:druid 脚本:user_info.sql
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for user_info
-- ----------------------------
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`password` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`realname` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`state` tinyint(4) NOT NULL,
PRIMARY KEY (`uid`) USING BTREE,
UNIQUE KEY `UK_f2ksd6h8hsjtd57ipfq9myr64` (`username`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of user_info
-- ----------------------------
INSERT INTO `user_info` VALUES ('1', 'admin', 'cf79ae6addba60ad018347359bd144d2', '管理员', '0');
INSERT INTO `user_info` VALUES ('2', 'testuser', 'cf79ae6addba60ad018347359bd144d2', '测试用户', '0');
3.1、修改cas.properties
增加配置
#mysql datasource
jdbc.url=jdbc\:mysql\://localhost\:3306/shiro?useUnicode\=true&characterEncoding\=UTF8&zeroDateTimeBehavior\=convertToNull&autoReconnect\=true&failOverReadOnly\=false&maxReconnects\=10
jdbc.username=root
jdbc.password=8888
3.2、数据源配置
增加配置文件:applicationContext-datasource.xml
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!--单点4.0.7升级:数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="1"/>
<property name="minIdle" value="1"/>
<property name="maxActive" value="20"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="validationQuery" value="SELECT 'x'"/>
<property name="testWhileIdle" value="true"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
<!-- PSCache(preparedStatement)对支持游标的数据库性能提升巨大,比如说Oracle/DB2/SQL Server,在mysql下建议关闭 -->
<property name="poolPreparedStatements" value="false"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="-1"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="wall,mergeStat"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- 实体类所在的包 对包中每个类进行注解扫描 省去逐一配置-->
<property name="packagesToScan">
<list><value>com.mac.sso.bean</value></list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.Dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl">update</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
</props>
</property>
</bean>
<!--单点4.0.7升级:工厂事物 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!--单点4.0.7升级:注解扫描-->
<context:component-scan base-package="com.mac.sso.*"/>
</beans>
3.3、pom文件修改
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
<!--阿里的连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.24</version>
</dependency>
<!--hutool轮子工具,非常好用,目前仅用来生成MD5密码-->
<!--jdk7做高支持4.*版本-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.17</version>
</dependency>