使用CAS在Tomcat中开发统一用户管理系统

与别的公司对接开发单点系统的客户端,领导讲最好我们也开发一套单点登录系统,于是自己研究了几天,也使用CAS开发了一套单点当了系统,记录步骤如下,以备以后参考:

一、服务端

1、下载cas,并配置成完整项目

下载地址:https://www.apereo.org/cas/download   

在Download CAS Server栏目下点击对应版本的zip即可下载,我下载的是cas-server-3.4.8

解压文件将modules下的cas-server-webapp-3.4.8.war为cas.war,拷贝到tomcat6下运行后,得到cas项目

把cas-server-webapp\src\main\java的类文件下拷贝到cas项目src里,然后把cas项目下的class文件里除了编译过的类以外全部拷贝到src里,这样就得到了cas整个项目。

2、验证用户及密码

把cas-server-support-jdbc-3.4.8.jar和ojdbc14.jar拷贝到lib下

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;

public final class CasDaoAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler
{
     public CasDaoAuthenticationHandler()
     {
     }
     public boolean authenticateUsernamePasswordInternal(UsernamePasswordCredentials credentials)
     {
         boolean bool = false;
         String username = credentials.getUsername();
         String password = credentials.getPassword();
         System.out.println("开始CAS认证......");
         System.out.println("userName:"+username);
         System.out.println("password:"+password);
      String driver = "oracle.jdbc.driver.OracleDriver";
       String conn_str_1 = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
       Connection conn =null;
       try {
        Class.forName(driver);
                 conn = DriverManager.getConnection(conn_str_1,"uums","pass");
                 String sql  = "SELECT password FROM SYS_USER WHERE LOGINNAME='"+username+"' ";//AND password='"+password+"'
                 ResultSet res = conn.prepareStatement(sql).executeQuery();
                 while(res.next()){
                   String psword = res.getObject(1).toString();
                   if(psword != null && (!"".equals(psword))){
                     if(password.equals(DecodeUtil.Decrypt(psword))){
                      System.out.println("认证成功!");
                         bool = true;
                         break;
                     }
                   }
                 }
       }
       catch (ClassNotFoundException e) {
        e.printStackTrace();
      }
       catch (SQLException e) {
        e.printStackTrace();
      }
       catch (Exception e) {
       e.printStackTrace();
      }
       finally{
       try{
        if(conn!=null)
         conn.close();
       }catch(Exception e){
        e.printStackTrace();
       }
      }
       if(!bool){
        System.out.println("认证不成功!");
       }
            return bool;
     }
     protected void afterPropertiesSetInternal()
         throws Exception
     {
//         super.afterPropertiesSetInternal();
     }
}

3、其他配置

a.在\WEB-INF\deployerConfigContext.xml 找到 <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"

p:httpClient-ref="httpClient" p:requireSecure="false"/>

参数p:requireSecure="false",是否需要安全验证,即HTTPS,false为不采用。

b.在/spring-configuration/ticketGrantingTicketCookieGenerator.xml和warnCookieGenerator.xml 找到

<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
  p:cookieSecure="false"
  p:cookieMaxAge="-1"
  p:cookieName="CASTGC"
  p:cookiePath="/cas" />

p:cookieSecure 为true 为采用https,false 为http,p:cookieSecure="true" 表示只能https请求才能读到cookie中的值,而http访问时不能从cookie中取的值.

p:cookieMaxAge 为-1 设置浏览器cookie保留时间 -1为浏览器关闭后失效,简单说是COOKIE的最大生命周期,-1为无生命周期,即只在当前打开的IE窗口有效,IE关闭或重新打开其它窗口,仍会要求验证。

4、为了信息传输将更加安全可以给tomcat配置https,SSL认证分双向认证和单向认证,如果为双向认证则客户端也需要安装已生成好的文件

1).双向认证配置步骤

第一次配置成功后,第二次在配置,始终不成功,中间没有出现错误,但是项目不能访问,还不知道什么原因,怀疑是证书冲突造成的,待以后查原因。

a.、生成服务器端证书

keytool -genkey -keyalg RSA -dname "cn=localhost,ou=sango,o=none,l=china,st=beijing,c=cn" -alias server -keypass password -keystore  d:\h
ttps\server.jks -storepass password -validity 3650

说明:

keytool :是个密钥和证书管理工具,

 -genkey:命令向某个尚不存在的密钥仓库添加数据时,就创建了一个密钥仓库

-keyalg :指定了用于生成密钥对的算法

RSA:公钥加密算法

-dname:指定证书拥有者信息,cn为要访问的域名或ip地址

“d:\https\server.jks”:含义是将证书文件的保存路径,证书文件名称是server.jks

“-validity 3650”:含义是证书有效期,3650表示10年,默认值是90天 “

-keypass:设置密码为password

b、生产客户端证书

keytool -genkey -keyalg RSA -dname "cn=sango,ou=sango,o=none,l=china,st=beijing,c=cn" -alias custom -storetype PKCS12 -keypass password -keystore d:\https\custom.p12 -storepass password -validity 3650

说明:

客户端的CN可以是任意值

-alias:产生别名,每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写
-storepass   指定密钥库的密码(获取keystore信息所需的密码) 

c、由于是双向SSL认证,服务器必须要信任客户端证书,因此,必须把客户端证书添加为服务器的信任认证。由于不能直接将PKCS12格式的证书 库导入,我们必须先把客户端证书导出为一个单独的CER文件,使用如下命令,先把客户端证书导出为一个单独的cer文件:

keytool -export -alias custom -file d:\https\custom.cer -keystore d:\https\custom.p12 -storepass password -storetype PKCS12 -rfc

然后,添加客户端证书到服务器中(将已签名数字证书导入密钥库)

keytool -import -v -alias custom -file d:\https\custom.cer -keystore  d:\https\server.jks -storepass password

d、查看证书

keytool -list -v -keystore d:\https\server.jks -storepass password

e、配置tomcat service.xml文件

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
  maxThreads="150" scheme="https" secure="true" 
     clientAuth="true" sslProtocol="TLS" 
     keystoreFile="D:\https\tomcat.keystore" keystorePass="password"
     truststoreFile="D:\https\tomcat.keystore" truststorePass="password"  /> 

说明:

protocol="org.apache.coyote.http11.Http11NioProtocol" :这样配置提供tomcat的响应速度

2)tomcat6配置单向认证 (未验证)

a、keytool -genkey -keyalg RSA -dname "cn=localhost,ou=sango,o=none,l=china,st=beijing,c=cn"
-alias server -keypass password -keystore d:\server.jks -storepass password -validity 3650  

keytool -genkey -keyalg RSA -dname "cn=localhost,ou=sango,o=none,l=china,st=beijing,c=cn" -alias server -keypass password -keystore server.jks -storepass password -validity 3650

2、由于是单向认证,没有必要生成客户端的证书,直接进入配置tomcat service.xml文件,Xml代码
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" 
maxThreads="150" scheme="https" secure="true" 
clientAuth="false" sslProtocol="TLS" 
keystoreFile="D:/server.jks" keystorePass="password"/>
clientAuth="false"表示单向认证,同时去掉truststoreFile="D:/server.jks" truststorePass="password"这2个属性

二、客户端

1、在http://downloads.jasig.org/cas-clients/,下载客户端,加压后把cas-client-core-3.2.1.jar放到项目的lib下

2、编写过滤器类

a.ClientFilter
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.authentication.AttributePrincipal;

public class ClientFilter implements Filter {
 
 String serviceUrl;
 String appName;
 String setSessionClass;
 public void destroy() {
  
 }

 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
   throws IOException, ServletException {
  AttributePrincipal principal = (AttributePrincipal) ((HttpServletRequest) request).getUserPrincipal();
  HttpSession session = ((HttpServletRequest) request).getSession();
  String userAccount = null;
  if (session.getAttribute("cas_username") == null && principal != null && principal.getName() != null ) {
   //具体项目有不同的情形:
   //1、所有的应用系统账号一致
   //2、所有的应用系统账号不一致

   /*1、若ezIDS的用户账号与第三方应用系统账号一致*/
   userAccount = principal.getName();
   /*若ezIDS的用户账号与第三方应用系统账号一致*/
   if(userAccount == null) {
    session.invalidate();
   }else{
    if(setSessionClass != null){
     try {
      SetLoginSession sls =  (SetLoginSession) Class.forName(setSessionClass).newInstance();
      sls.setSession(userAccount, (HttpServletRequest) request);
     } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e);
     }
    }
    session.setAttribute("cas_username", principal.getName());
   }
  }
  chain.doFilter(request, response);
 }

 public void init(FilterConfig arg0) throws ServletException {
  setSessionClass = arg0.getInitParameter("setSessionClass");
 }
 
}

b.SetLoginSession

import javax.servlet.http.HttpServletRequest;

public interface SetLoginSession {
 public void setSession(String username, HttpServletRequest request);
 public boolean isLogined(HttpServletRequest request);
}

c.YcyySetLoginSession
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import modules.sys.Sys_user;
import modules.sys.Sys_userCtl;

public class YcyySetLoginSession implements SetLoginSession {
 public void setSession(String username, HttpServletRequest request) {
     request.getSession().setAttribute("org.apache.struts.action.LOCALE", Locale.CHINA);
     HttpSession session = request.getSession();    
     Sys_user user = new Sys_userCtl().logon(username,request.getRemoteAddr());
     session.setAttribute("userSession", user);
 }

 public boolean isLogined(HttpServletRequest request) {
  return request.getSession().getAttribute("userSession") != null;
 }
}

 3、配置web.xml

<!--单点登录相关配置开始-->
 <!-- 用户的身份认证 --> 
 <filter>
  <filter-name>CASFilter</filter-name>
  <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
  <init-param>
   <param-name>casServerLoginUrl</param-name> <!-- 59.203.198.2:7080 192.168.0.149:8080-->
   <param-value>http://192.168.0.149:8080/cas/login</param-value>
  </init-param>
  <init-param>
   <param-name>renew</param-name>
   <param-value>false</param-value>
  </init-param>
  <init-param>
   <param-name>gateway</param-name>
   <param-value>false</param-value>
  </init-param>
  <init-param>
   <param-name>serverName</param-name>
   <param-value>http://192.168.0.149:8080</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>CASFilter</filter-name>
  <url-pattern>/private/index.xp</url-pattern>
 </filter-mapping>
 <!-- 用户的身份认证 -->

 <!-- 负责Ticket的校验 -->
 <filter>
  <filter-name>CAS Validation Filter</filter-name>
  <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
  <init-param>
   <param-name>casServerUrlPrefix</param-name>
   <param-value>http://192.168.0.149:8080/cas</param-value>
  </init-param>
  <init-param>
   <param-name>serverName</param-name>
   <param-value>http://192.168.0.149:8080</param-value>
  </init-param>
  <init-param>
   <param-name>useSession</param-name>
   <param-value>true</param-value>
  </init-param>
  <init-param>
   <param-name>redirectAfterValidation</param-name>
   <param-value>true</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>CAS Validation Filter</filter-name>
  <url-pattern>/private/index.xp</url-pattern>
 </filter-mapping>
 <!-- 负责Ticket的校验 -->

 <!--该过滤器负责实现HttpServletRequest请求的包裹,比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名-->
 <filter>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <url-pattern>/private/index.xp</url-pattern>
 </filter-mapping>
 <!--该过滤器负责实现HttpServletRequest请求的包裹,比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名-->

 <!--该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。比如AssertionHolder.getAssertion().getPrincipal().getName()-->
 <filter>
  <filter-name>CAS Assertion Thread Local Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>CAS Assertion Thread Local Filter</filter-name>
  <url-pattern>/private/index.xp</url-pattern>
 </filter-mapping>
 <!--该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。比如AssertionHolder.getAssertion().getPrincipal().getName()-->

 <!--YCYY设置session使用的过滤器-->
 <filter>
        <filter-name>setnameFilter</filter-name>
        <filter-class>modules.com.casFilter.ClientFilter</filter-class>
  <init-param>
   <param-name>setSessionClass</param-name>
   <param-value>modules.com.casFilter.YcyySetLoginSession</param-value>
  </init-param>
 </filter>
 <filter-mapping>
     <filter-name>setnameFilter</filter-name>
     <url-pattern>/private/index.xp</url-pattern>
 </filter-mapping>
 <!--YCYY设置session使用的过滤器-->
 <!--单点登录相关配置结束-->
</web-app>

三、遇到的问题

1、在请求服务器端时,会很慢,那是因为在top.jsp加了引用到https://ajax.googleapis.com网站的jquery,但是该网站不能进行访问了,所以会很慢,去掉后就可以了。

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值