zoukankan      html  css  js  c++  java
  • CAS单点登录(SSO)

    1.概念

    CAS:Java (Spring Webflow/Spring Boot) 服务组件,可插拔身份验证支持(LDAP,Database,X.509,MFA),支持多种协议(CAS, SAML, OAuth, OpenID, OIDC),跨平台客户端支持(Java, .Net, PHP, Perl, Apache等),与uPortal,Liferay ,BlueSocket,Moodle, Google Apps等集

    SSO:单点登录简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。域,跨域,Session跨域,Nginx Session共享:分别在session,nginx中已有

    2.SSL/TLS/HTTPS之间的关系

    SSL(Secure Sockets Layer 安全套接层),为Netscape所研发,用以保障在Internet上数据传输之安全,SSL一般是https的代名词,TLS(Transport Layer Security,传输层安全)是在SSL3.0的基础上发展的,继承了SSL的优点,都是用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取及窃听。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。

    SSL协议可分为两层:

    SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。

    SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

    3.HTTPS的数据的加密传输

     浏览器把协议版本号,支持的加密算法生成的随机数A发送给服务器,服务器接到客户端发送过来的加密算法后,查看自身支持的加密算法,确定双方后边使用哪种加密算法,然后把该算法和数字证书以及生成的随机数B发给客户端,客户端接到服务器发送过来的证数后,得到证书里的非对称加密的公钥D,然后又生成一个随机数C,把C和D加密后得到的一个字符串E发给服务器。服务器接到这个字符串E后,用自身的私钥解密得到C,这样服务器就集齐了 A,B,C,然后利用ABC生成对话加密密钥 , 因为客户端也得到了A,B,C 这样双方都能进行加密解密了,至于加密解密的算法就是前面双方交换加密方法时约定的加密算法。所以可以看出ABC中,只有C是极难被别人得到的,这样保证了安全性,同时这个过程前面用到了非对称加密,一旦加密密钥确定,后面其实用的都是对称加密了。

    4.使用java的keytool制作证书

    keytool -genkeypair -alias serverkey -keypass 111111 -storepass 111111 
        -dname "C=CN,ST=GD,L=SZ,O=vihoo,OU=dev,CN=vihoo.com" 
        -keyalg RSA -keysize 2048 -validity 3650 -keystore server.keystore
    

    keytool用法  

    -rfc" 表示以base64输出文件,否则以二进制输出。      

    -startdate <startdate>          证书有效期开始日期/时间

    -alias 实体别名(包括证书私钥)

    -certreq            生成证书请求

    -changealias        更改条目的别名

    -dname 指定证书拥有者信息 例如: “CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名称,ST=州或省份名称,C=单位的两字母国家代码”

    -destalias <destalias>          目标别名

    -ext <value>                    X.509 扩展

    -exportcert         导出证书

    -export 将别名指定的证书导出到文件 keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码

    -storetype <storetype>  密钥库类型

    -genkeypair  生成密钥对

    -genseckey  生成密钥

    -genseckey          生成密钥

    -gencert            根据证书请求生成证书

    -keystore 指定密钥库的名称(产生的各类信息将不在.keystore文件中)

    -keyalg 指定密钥的算法 (如 RSA DSA(如果不指定默认采用DSA))

    -keysize 指定密钥长度

    -keypass 指定别名条目的密码(私钥的密码)

    -validity 指定创建的证书有效期多少天

    -printcertreq       打印证书请求的内容

    -printcrl           打印 CRL 文件的内容

    -providername <providername>    提供方名称

    -providerclass <providerclass>  提供方类名

    -providerarg <arg>              提供方参数

    -providerpath <pathlist>        提供方类路径

    -protected                      通过受保护的机制的口令

    -importcert         导入证书或证书链

    -importkeystore     从其他密钥库导入一个或所有条目

    -storepass 指定密钥库的密码(获取keystore信息所需的密码)

    -list 显示密钥库中的证书信息 keytool -list -v -keystore 指定keystore -storepass 密码

    -v 显示密钥库中的证书详细信息

    -file 参数指定导出到文件的文件名

    -delete 删除密钥库中某条目 keytool -delete -alias 指定需删除的别 -keystore 指定keystore -storepass 密码

    -printcert 查看导出的证书信息 keytool -printcert -file yushan.crt

    -keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore sage

    -storepasswd 修改keystore口令 keytool -storepasswd -keystore e:yushan.keystore(需修改口令的keystore) -storepass 123456(原始密码) -new yushan(新密码)

    -sigalg <sigalg>                签名算法名称

    -import 将已签名数字证书导入密钥库 keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书

    5.keytool实例

    生成keystore

    keytool -genkeypair -alias tomcat -keyalg RSA -validity 3650 -keysize 1024 -keystore H:/ajava/caskey/test.keystore
    

    注意

    cas.test.com 必须与如下保持一致

    否则会出如下错误

    No name matching localhost found

    导出证书,注意-alias tomcat  与上述的别名需要一致

    keytool -keystore  H:/ajava/caskey/test.keystore   -export  -file  H:/ajava/caskey/test.cer -alias  tomcat  -storepass 123456
    

     可以查看详情

    keytool -list -keystore  H:/ajava/caskey/test.keystore -storepass 123456  
    

     打印证书

    keytool -printcert -file H:/ajava/caskey/test.cer   //可以添加-v
    

     

    客户端导入证书(jdk导入证书,否则java不信任会出现错误)

    keytool -import -keystore F:JAVAjdk1.8jrelibsecuritycacerts  -file  H:/ajava/caskey/cas.cer   -alias tomcat
    

    注意:cacerts这个名字必须是cacerts,因为cacerts是java信任的证书库(启动时的jdk),否则会出现如下错误,且密码必须是changeit。否则会出现如下错误

    生成后缀.p12的证书

    keytool -genkeypair -alias mykey  -keyalg RSA  -storetype PKCS12  -validity 3650 -keysize 1024 -keystore H:/ajava/caskey/mykey.p12
    

     在tomcat中使用(服务端)

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
                   maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
    		       clientAuth="false" sslProtocol="TLS"
    		       keystoreFile="H:/ajava/caskey/test.keystore" keystorePass="123456" />
    

    这里没有采用客户端认证

    备注:

    keystoreFile:第一步创建key存放的位置

    keystorePass:创建证书时的密码

    truststoreFile:验证客户端证书的根证书

    truststorePass:创建证书时的密码

    假如客户端使用了验证时,需要在浏览器导入相应的证书

    这里的例子没有采用客户端验证

    6.使用cas实现单点登录

    服务端

    下载cas服务器    https://github.com/apereo/cas-overlay-template/tree/5.3

    官方文档   https://github.com/apereo/cas

    添加到Idea中,修改pom,添加如下依赖,重新打包

    其中比较重要的配置如下

    log4j2.xml

    配置日志文件位置(这里log4j,log4j2,logback 都差不多类似)

           <Property name="cas.log.dir" >.</Property>   
            <!-- To see more CAS specific logging, adjust this property to info or debug or run server with -Dcas.log.leve=debug -->
            <Property name="cas.log.level" >warn</Property>
    

    web-inf下的application.properties文件,假如不愿意更改原配置,那么可以在src/resources先新建application.properties,根据springboot的配置文件加载原则,会优先加载src/resources下的application.properties,密码啥的是有效的,但是application.yml,application.properties中配置的tomcat相关的配置,打成war包部署在独立的tomcat上之后, 会失效,原因是因为spring boot内置的tomcat,也就是说如下配置只对springboot启动有效,这里采用的是tomcat(所以如下都注释了),上面已经配置了,tomcat启动可以采用上述介绍的方法(重新打war包)修改配置,也可以解压后修改配置,解压后需要删除war,否则每次启动都会先解压。

    #页面
    #server.context-path=/cas
    #端口
    #server.port=8443
    #证书的位置 .keystore文件的位置
    #server.ssl.key-store=H:/ajava/caskey/test.keystore
    #指定密钥库的密码 -storepass
    server.ssl.key-store-password=123456
    #别名条目的密码-keypass
    #server.ssl.key-password=123456
    #用户名与密码
    #cas.authn.accept.users=casuser::Mellon

    开启服务端,密码cas.authn.accept.users=casuser::Mellon

        

    不使用ssl(https)那么需要在application.properties文件中添加,文件位置WEB-INFclassesapplication.properties

    #关闭https验证
    cas.tgc.secure=false

    CAS 未认证授权服务需要在application.properties文件中添加

    #开启识别json文件,默认false
    cas.serviceRegistry.initFromJson=true

    在application.properties文件中添加cas.serviceRegistry.initFromJson=true实际是扫描json文件,serviceId表示允许匹配的地址,文件位置WEB-INFclassesservicesHTTPSandIMAPS-10000001.json

    {
      //该文件可以是多个,但是该文件名需要满足如下name+id+.json
      //加载的类,这里必须使用这个类
      "@class" : "org.apereo.cas.services.RegexRegisteredService",
      //能匹配的url,能够匹配多个,也可以使用正则,假如需要添加http,那么编程"serviceId" : "^(https|imaps|http)://.*",,也就是运行通过的域
      "serviceId" : "^(https|imaps|http)://.*",
      //服务名
      "name" : "HTTPS and IMAPS",
      //id,唯一标识符
      "id" : 10000001,
      //描述
      "description" : "This service definition authorizes all application urls that support HTTPS and IMAPS protocols.",
      //定义多个服务器的执行顺序,数字越大优先级越低
      "evaluationOrder" : 10000
    }

    假如serviceId不能匹配会出现没有授权的错误

    客户端

    https://github.com/apereo/java-cas-client   客户端下载

     客户端配置web.xml

    <!--退出过滤器-->
        <filter>
            <filter-name>CAS Single Sign Out Filter</filter-name>
            <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
            <init-param>
                <param-name>casServerUrlPrefix</param-name>
                <param-value>https://cas.test.com:8443/cas</param-value>
            </init-param>
        </filter>
        <!--退出监听器-->
        <listener>
            <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
        </listener>
        <!--认证过滤器-->
        <filter>
            <filter-name>CAS Authentication Filter</filter-name>
            <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
         <!--没有通过认证重定向的页面--> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>https://cas.test.com:8443/cas/login</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://localhost:9002</param-value> </init-param> </filter> <!--验证过滤器--> <filter> <filter-name>CAS Validation Filter</filter-name> <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class> <init-param> <param-name>casServerUrlPrefix</param-name> <param-value>https://cas.test.com:8443/cas</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://localhost:9002</param-value> </init-param> <init-param> <param-name>redirectAfterValidation</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>useSession</param-name> <param-value>true</param-value> </init-param> </filter> <!-- 该过滤器负责实现HttpServletRequest请求的包裹--> <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 Single Sign Out Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CAS Validation Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CAS Authentication Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

    测试

    7. 配置数据库密码认证及md5加密,当然也可以使用其他方式加密。

    使用JDBC与MD5

    依赖

    <!-- 数据库驱动 --> 
    <dependency> 
        <groupId>mysql</groupId> 
        <artifactId>mysql-connector-java</artifactId> 
        <version>5.1.21</version> 
    </dependency> 
    
    <!--jdbc认证需要添加的,这个是cas的依赖包--> 
    <dependency>
         <groupId>org.apereo.cas</groupId> 
        <artifactId>cas-server-support-jdbc</artifactId> 
        <version>${cas.version}</version> 
    </dependency>
    

    在application.properties文件中可添加额配置,绿色表示必须

    #Query Database Authentication 数据库查询校验用户名开始 
    #查询账号密码sql,必须包含密码字段
    cas.authn.jdbc.query[0].sql=select * from sys_user where username=?
    #指定上面的sql查询字段名(必须,密码)
    cas.authn.jdbc.query[0].fieldPassword=password
    #指定过期字段,1为过期,若过期不可用
    cas.authn.jdbc.query[0].fieldExpired=expired
    #为不可用字段,1为不可用,需要修改密码
    cas.authn.jdbc.query[0].fieldDisabled=disabled
    #数据库方言(hibernate的知识)
    cas.authn.jdbc.query[0].dialect=
    #数据库驱动
    cas.authn.jdbc.query[0].driverClass=
    #数据库连接
    cas.authn.jdbc.query[0].url=
    #数据库用户名
    cas.authn.jdbc.query[0].user=
    #数据库密码
    cas.authn.jdbc.query[0].password=
    #默认加密策略,通过encodingAlgorithm来指定算法,默认NONE不加密
    cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
    cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
    cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
    #Query Database Authentication

    若密码无加密,调整passwordEncoder.type=NONE
    若密码加密策略为SHA,调整passwordEncoder.encodingAlgorithm=SHA
    若算法为自定义,实现org.springframework.security.crypto.password.PasswordEncoder接口,并且把类名配置在passwordEncoder.type

    对密码进行盐值处理再加密,增加了反查难度,如上面的例子,对密码只是简单的加密,不同的帐号有可能相同的值,能判断出密码是一致,但通过此方案,大大增加了难度,所以安全系数也高了许多,推荐策略

    #Encode Database Authentication 开始 
    #加密次数
    cas.authn.jdbc.encode[0].numberOfIterations=2
    #该列名的值可替代上面的值,但对密码加密时必须取该值进行处理
    cas.authn.jdbc.encode[0].numberOfIterationsFieldName=
    #盐值固定列
    cas.authn.jdbc.encode[0].saltFieldName=username
    #静态盐值
    cas.authn.jdbc.encode[0].staticSalt=.
    cas.authn.jdbc.encode[0].sql=select * from sys_user_encode where username=?
    #对处理盐值后的算法
    cas.authn.jdbc.encode[0].algorithmName=MD5
    cas.authn.jdbc.encode[0].passwordFieldName=password
    cas.authn.jdbc.encode[0].expiredFieldName=expired
    cas.authn.jdbc.encode[0].disabledFieldName=disabled
    cas.authn.jdbc.encode[0].url=
    cas.authn.jdbc.encode[0].dialect=
    cas.authn.jdbc.encode[0].user=sa
    cas.authn.jdbc.encode[0].password=
    cas.authn.jdbc.encode[0].driverClass=
    #Encode Database Authentication 结束

     8. 退出

    #允许发出退出控制退出后转发url
    cas.logout.followServiceRedirects=true
    

     退出后跳转到指定页面,假如只有https://ip/cas/logout,那么会跳到注销页面

    <a  href ="https://ip/cas/logout?service=https://demo.testcas.com/cas-server/login" />
    

     如下配置(不需要配置)

    cas.logout.redirectParameter=service#上面a href的service的由来
    cas.logout.confirmLogout=false #是否需要出现confirm窗口
    cas.logout.removeDescendantTickets=false #是否需要移除Ticket
  • 相关阅读:
    Mybatis批量插入,是否能够返回id列表
    SVN和Git代码管理小结
    SVN和Git代码管理小结
    Spring异步执行(@Async)2点注意事项
    Spring异步执行(@Async)2点注意事项
    2015年工作中遇到的问题101-110
    Codeforces 263B. Appleman and Card Game
    Codeforces 263A. Appleman and Easy Task
    HDU 482 String
    字符串hash-BKDRHash
  • 原文地址:https://www.cnblogs.com/gg128/p/9897918.html
Copyright © 2011-2022 走看看