目录

1 概要介绍
2 单点登录服务架构介绍
3 开发过程
3.1 环境准备
3.1.1 快速搭建
3.1.2 分步骤搭建
3.2 接口开发
3.2.1 CAS服务端接口开发
3.2.2 dataviz客户端接口开发
3.2.3 3rd-app客户端接口开发
3.2.4 注意事项
4 工程打包部署
4.1 CAS服务端工程打包部署
4.2 dataviz客户端工程打包部署
4.3 3rd-app客户端工程打包部署
5 应用效果展示
6 附录:CAS单点登录实现原理详解
6.1 用户第一次访问dataviz
6.2 用户第二次访问dataviz
6.3 用户在登录状态下第一次访问3rd

1 概要介绍

单点登录是指在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。CAS是目前Java服务器环境下使用最为广泛的单点登录实现方案,由于CAS服务配置复杂,不了解CAS的项目开发人员上手搭建CAS服务较为困难。所以本文提供了CAS单点登录Demo工程以及代码样例,项目开发人员可以直接使用此工程搭建CAS服务,也可以基于此工程进行二次开发,为DataViz和其它应用系统的单点登录提供快速实现。

2 单点登录服务架构介绍

000

如图所示,上图包含CAS单点登录服务端、dataviz服务端、自定义第三方服务端等3个服务端和1个用户端,用户简单的登录流程如图中数字标号所示:

  1. 当用户端第一次访问dataviz服务端的时候,处于未登录状态,无法正常访问;
  2. 用户会先到CAS单点登录服务端做登录验证;
  3. 用户登录验证通过后CAS单点登录服务端会告知dataviz服务端用户处于已登录状态,此时,用户才可以正常访问dataviz端;
  4. 当用户想直接通过dataviz服务端跳转到自定义第三方服务端进行访问;
  5. 此时,CAS单点登录服务端会告知自定义第三方服务端用户处于已登录状态,因此,用户可以正常访问该服务端资源;

3 开发过程

3.1 环境准备

3.1.1 快速搭建

为了方便大家能够快速搭建实现单点登录的开发环境,我们提供了完整的”All in one“的开发环境,内部包含eclipse、tomcat、源码工程等所有资源,不需要任何配置,下载解压缩之后即可运行,需要下载此环境请联系产品技术支持团队获取 l-rui@neusoft.com。

  • 下载dataviz-cas-demo.zip 文件

  • 将下载的dataviz-cas-demo.zip文件解压缩,必须放置在windows系统D盘的根目录下,dataviz-cas-demo文件夹的内容如下图所示。

    【注意为确保此环境不需要任何改动即可使用,请严格按照如下图的路径放置,不要移动到其他位置】

    001

    002

  • 双击eclipse.exe,进入到eclipse代码编辑器中,可以看见所有的工程已经配置好,然后根据3.1.2.6.4节配置工程依赖文件的说明配置工程依赖文件。

  • 接下来只需要按照3.2节接口开发的文档进行配置即可。

3.1.2 分步骤搭建

以上环境如果已经搭建好,请略过本章节。

如果希望基于已有的eclipse等环境分步骤搭建开发环境,请阅读本章节。本章节介绍的是如何从零开始搭建好开发环境。

本章节建议使用如下开发软件:

  • JDK
  • Eclipse
  • apache-tomcat
  • gradle

3.1.2.1 JDK安装与配置

  • 启动JDK安装程序,一直点击下一步即可;

    003

3.1.2.2 Tomcat安装与配置

  • 启动Tomcat安装程序,一直点击下一步即可;

    004

3.1.2.3 Gradle安装与配置

  • 解压gradle-2.14.zip安装包到指定路径。

    005

3.1.2.4 Maven安装与配置

  • 解压apache-maven-3.6.2.zip安装包到指定路径。

    006

3.1.2.5 Eclipse安装与配置

  • 解压eclipse.zip安装包到指定路径;

    007

  • 启动eclipse点击Window->Preferences,如下图所示,选中Gradle(STS)->填入gradle-2.14的文件路径->点击Apply and Close;

    008

  • 启动eclipse点击Window->Preferences,如下图所示,选中Maven->User Settings->填入apache-maven-3.6.2中conf文件夹中settings.xml的文件路径->点击Apply and Close;

    009

  • 启动eclipse点击Window->Preferences,如下图所示,依次进行如下操作,添加tomcat容器到eclipse中;

    010

    011

  • 点击Servers选项->点击蓝色下划线处->选中Tomcat v8.5 Server->Finish,下图左侧出现Servers文件夹表示配置成功;

    012

    013

3.1.2.6 工程下载与导入

单点登录Demo工程分为三个部分,分别是:

  • CAS服务端工程,提供单点登录服务,对应的工程是dataviz-sso-cas-overlay和dataviz-sso-cas-extension工程;
  • dataviz客户端,提供dataviz服务,对应的工程是dataviz-sso-cas-client工程;
  • 3rd-app客户端,验证单点登录是否成功的自定义服务,对应的工程是3rd-app-demo工程;
3.1.2.6.1 CAS服务端工程导入
  1. 在Project Explorer中右键会出现以下弹出框,点击Import...->Gradle(STS) Project->Browser选择工程路径->Build Model->选中生成的文件->Finish;

    014

    015

    016

3.1.2.6.2 dataviz客户端工程导入
  1. 在Project Explorer中右键会出现以下弹出框,点击Import...->Gradle(STS) Project->Browser选择工程路径->Build Model->选中生成的文件->Finish;

    014

    015

    017

3.1.2.6.3 3rd-app客户端工程导入
  1. 在Project Explorer中右键会出现以下弹出框,点击Import...->Maven Project->Browser选择工程路径->Build Model->选中生成的文件->Finish;

    014

    018

    019

    3.1.2.6.4 配置工程依赖文件
  2. 对于Gradle工程,配置过程如下:选中3个Gradle工程->Gradle(STS)->Refresh All;

    020

  3. 对于Maven工程,配置过程如下:选中demo工程->Maven->Update Project...;

    021

3.2 接口开发

3.2.1 CAS服务端接口开发

由于CAS集成后,所有应用的登录都需要在CAS端(包含用户的认证、登录界面的自定义),因此除了示例工程,正式的CAS集成总是会需要进行CAS端的开发构建。一般来说,可能需要开发的内容有几个方面:

  1. 登录界面修改

  2. 新的认证方式,如:加密的登录密码

  3. 自定义的CAS客户端维护

3.2.1.1 CAS服务端的工程结构

在介绍上述开发内容之前,本文先介绍下CAS服务端的工程结构。

022 023

如上图所示,dataviz-sso-cas-overlay/src/main/webapp 下存放的是CAS应用中需要修改或添加的配置及页面等内容,dataviz-sso-cas-extension/src/main/java 下存放的是后续扩展所需的Java类代码,比如:登录密码的加密等功能的实现。

  • cas.properties是CAS的重要配置文件,包含了众多properties配置,具体配置下文会详细介绍。
  • ticketGrantingTicketCookieGenerator.xml配置文件用于配置CAS服务端是否使用HTTPS安全连接,当p:cookieSecure="false"表明使用HTTP连接,p:cookieSecure="true"表明使用HTTPS连接,本工程默认使用HTTP连接。

    024

  • deployerConfigContext.xml用于配置Spring Bean,如果需要自定义Bean,需要在此文件中配置。

以上介绍的是该工程的基础配置文件,其它配置文件会在工程扩展章节详细介绍。

3.2.1.2 基本配置修改

  • cas.properties是CAS的重要配置文件,包含了众多properties配置。下图展示出该文件中需要修改的部分,其他配置通常不用修改,如需修改请自行查看配置文件,文件中有相应的注释说明。

      # CAS服务的访问地址(只需要配置地址和端口即可)  
      server.name=http://sso.com:8080  
      server.prefix=${server.name}/dataviz-sso-cas-overlay
      # 数据库配置,您需要指定一个数据库,并设计一张表用于存储账号和密码。
      database.driverClass=com.mysql.jdbc.Driver
      database.url=jdbc:mysql://sso.com:3306/cas?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
      database.user=root
      database.password=root
      #查询用户密码的SQL
      database.authenticationSQL=select password from t_user where username = ?
    

    上文的database.authenticationSQL指的是存放用户账号信息的数据库表,查询出来的密码用于验证用户输入的密码是否正确。

3.2.1.2 登录界面修改

top.jsp、bottom.jsp、casLoginView.jsp、messages.properties四个文件构成了登录界面。

  • 如需修改登录界面,如下图所示,可以直接修改casLoginView.jsp文件的样式即可,必须保留标签里的内容,这个标签涉及到登录的逻辑,没有特殊需求的情况下不要修改。

  • 标签引入了top.jsp、bottom.jsp,通常不需要修改。

  • messages.properties包含了登录界面的文字等内容,通过来获取。

    025

3.2.1.3 登录密码加密

CustomEncodePassword.java文件实现了登录密码加密的内容。如需使用登录密码加密功能,需要先在deployerConfigContext.xml文件中配置对应的Bean,如下所示,需要先注释掉QueryDatabaseAuthenticationHandler类路径的Bean,配置CustomEncodePassword类路径的Bean。

<!-- <bean id="dbAuthHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler" p:dataSource-ref="dataSource" p:sql="${database.authenticationSQL}" /> -->
<bean id="dbAuthHandler" class="com.neusoft.dataviz.service.CustomEncodePassword" p:dataSource-ref="dataSource" p:sql="${database.authenticationSQL}" />

下图给出了,本工程自定义登录密码加密的默认逻辑。

  • transformedCredential.getPassword()表示获取用户输入的登录密码;
  • transformedCredential.getUsername()表示用户输入的用户名;
  • getJdbcTemplate().queryForObject(sql, String.class, username)表示查询数据库中的密码,sql语句是指在cas.properties配置的database.authenticationSQL属性;
  • 然后用户可以自定义密码加密方式和比对方法,验证通过后将用户信息返回;

    026

3.2.1.4 自定义的CAS客户端

CAS客户端需要事先注册到CAS服务端中,这样才能真正的实现单点登录。dataviz-sso-cas-client.json和3rd-app-demo.json是本工程默认提供的单点登录客户端配置文件,分别对应dataviz客户端和3rd-app客户端。以dataviz-sso-cas-client.json为例,当你需要添加新的客户端的时候,需要添加如下配置,主要修改serviceId、name、id、description,其他属性不需要修改。

  • serviceId指的是客户端的访问路径,(?:/.*)?是一种模糊匹配方式,采用本文提供的方式即可(http://dataviz.com:8080/dataviz-service是dataviz客户端的访问路径)
  • name和description是客户端的名称和描述,可以自定义
  • id需要与其他自定义客户端不同,每个客户端是独立的,不能有相同的id号
{
  "@class" : "org.jasig.cas.services.RegexRegisteredService",
  "serviceId" : "http://dataviz.com:8080/dataviz-service(?:/.*)?",
  "name" : "dataviz-sso-cas-client",
  "id" : 999,
  "description" : "dataviz-sso-cas-client",
  "proxyPolicy" : {
    "@class" : "org.jasig.cas.services.RefuseRegisteredServiceProxyPolicy"
  },
  "evaluationOrder" : 1,
  "usernameAttributeProvider" : {
    "@class" : "org.jasig.cas.services.DefaultRegisteredServiceUsernameProvider"
  },
  "logoutType" : "BACK_CHANNEL",
  "attributeReleasePolicy" : {
    "@class" : "org.jasig.cas.services.ReturnAllowedAttributeReleasePolicy",
    "principalAttributesRepository" : {
      "@class" : "org.jasig.cas.authentication.principal.DefaultPrincipalAttributesRepository"
    },
    "authorizedToReleaseCredentialPassword" : false,
    "authorizedToReleaseProxyGrantingTicket" : false
  },
  "accessStrategy" : {
    "@class" : "org.jasig.cas.services.DefaultRegisteredServiceAccessStrategy",
    "enabled" : true,
    "ssoEnabled" : true
  }
}

3.2.2 dataviz客户端接口开发

027

  • 上图中的CasAuthenticationEntryPointWithAjaxSupport.java类是用于和CAS服务端通信的类,通常情况下不用修改;
  • 重要的是CasUserDetailService.java类,dataviz客户端是基于spring security 进行安全认证的,所以这个类是用来获取CAS服务端传给dataviz客户端的登录用户名的。如下图所示,通过重写loadUserByUsername方法来验证该用户的有效性,如果该用户有效,直接将该用户对象返回给前端,spring security会自动保存用户的session。
public class CasUserDetailService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String loginName) {
        //填写获取用户对象的逻辑,并且构造返回DefaultUser对象
        DefaultUser user = new DefaultUser(loginName, "");
        return user;
    }
}

3.2.3 3rd-app客户端接口开发

028

上图是3rd-app客户端的工程结构,该工程基于spring boot构建。用于验证和dataviz客户端是否能相互跳转。

  • application.properties包含CAS服务端和3rd-app客户端的配置,基本配置如下所示。

      # CAS服务端的访问路径
      cas.server-url=http://sso.com:8080/dataviz-sso-cas-overlay
      # 3rd-demo的域名和端口
      cas.client-host=http://3rd-demo.com:8080/3rd-app/login
    
  • 该工程提供了两个接口,可以在IndexControll.java文件中查看,分别是http://3rd-demo.com:8080/loginhttp://3rd-demo.com:8080/logout接口,分别对应着登录和登出,如下图所示,在"/login"接口中,可以通过CasUtil.getLoginNameFromCas(req)方法获取到从CAS服务端传递过来的用户名loginName,进而返回给3rd-demo客户端进行处理,本文默认直接将该用户名loginName显示在前端。

public class IndexController {

    @GetMapping("/login")
    public ModelAndView index(HttpServletRequest req) {
        ModelAndView mv = new ModelAndView();
        //从CAS服务端获取用户信息,发给前端
        String loginName = CasUtil.getLoginNameFromCas(req);
        if (StringUtils.isEmpty(loginName)) throw new RuntimeException("用户名为空");
        mv.setViewName("index");
        mv.addObject("loginName",loginName);
        return mv;
    }

    @GetMapping("/logout")
    public String logout(HttpSession httpSession) {
        //清空session
        httpSession.invalidate();
        //重定向到CAS服务端
        return "redirect:http://localhost:8080/dataviz-sso-cas-overlay/logout?service=http://localhost:8080/3rd-app/login";
    }
}

3.2.4 注意事项

为了便于用户理解,接口开发时,涉及到的如properties、json等配置文件中包含的IP地址均有sso.com、dataviz.com、3rd-demo.com等域名代替,请以实际的IP地址为准,对配置文件中的IP地址做出相应的修改。

4 工程打包部署

4.1 CAS服务端工程打包部署

  • 首先,如下图所示,点击Gradle(STS) build...,并在Edit Configuration输入clean assemble并点击Run。

    029

    030

  • 把打包好的文件复制到Tomcat的webapps文件夹下。

    031

    032

4.2 dataviz客户端工程打包部署

  • 首先,如下图所示,点击Gradle(STS) build...,并在Edit Configuration输入clean assemble并点击Run。

    033

    034

    035

  • 将dataviz-sso-cas-client.jar包放入dataviz-service.war/WEB-INF/lib文件夹下。

    036

  • 将下图中红色箭头指向的两个jar包放入dataviz-service.war/WEB-INF/lib。

    037

  • 将dataviz-service/WEB-INF/conf/spring/applicationContext-security.xml.sso.cas修改为applicationContext-security.xml,并将原来的applicationContext-security.xml备份。

  • 将dataviz-service/WEB-INF/web.xml.sso.cas修改为web.xml,并将原来的web.xml备份。
  • 修改dataviz-service/WEB-INF/conf/dataviz-sso-cas-client.properties文件,如下所示。根据实际配置修改对应的IP和端口号。

      # cas 服务访问地址
      sso.cas.casServer=http://sso.com:8080/dataviz-sso-cas-overlay
    
      # cas 服务内部地址,用于内部验证通信,当仅在内网使用或没有内外网隔离时可与外部访问地址相同
      sso.cas.casServerLocal=http://sso.com:8080/dataviz-sso-cas-overlay
    
      # DataViz 后台应用访问地址
      sso.cas.localServer=http://dataviz.com:8080/dataviz-service
    
      # DataViz 登录地址,不用修改
      sso.cas.localServicePath=/login/cas
    
      # DataViz 登出地址,不用修改
      sso.cas.localLogoutPath=/logout/cas
    
      # DataViz 前台访问地址
      sso.cas.defaultTargetRedirect=http://dataviz.com:8886/dataviz_web/src/index.html
    
  • 修改dataviz_web工程中common/config.js文件夹的内容如下所示。

      // cas登录地址
      window.cas_server = "http://sso.com:8080/dataviz-sso-cas-overlay";
      // cas服务回调地址
      window.cas_callback_server = "?service=http://dataviz.com:8080/dataviz-service/login/cas";
      // 是否使用cas登录
      window.isCasLogin = true;
    
  • 将dataviz-sso-cas-overlay.war放到和dataviz-service同级目录下。

  • 如果是linux系统,则输入命令./startup.sh启动Tomcat;如果是windows系统,则双击startup.bat启动Tomcat,本文使用windows系统,启动方式如下图所示。

    038

4.3 3rd-app客户端工程打包部署

  • 首先,如下图所示,点击Maven install。
    046

  • 如下图所示,得到工程war包。
    039

  • 将3rd-app.war放到和dataviz-sso-cas-overlay.war同级目录下。

  • 启动方式和上文相同。

5 应用效果展示

为了演示单点登录功能效果,本文设计了如下访问流程:

  • 如下图所示,首次访问dataviz服务,发现页面跳转到了CAS单点登录服务端;

    040

  • 输入账号密码登录后,发现页面跳转到了dataviz首页;

    041

  • 此时,访问http://3rd-app.com:8080/3rd-app/login,该地址是3rd-demo的接口,可以看到,用户无需登录就可以直接进入3rd-demo系统的首页;

    042

  • 点击退出登录,发现页面跳转回CAS服务端登录页;

    043

  • 此时,刷新dataviz系统的首页,页面也跳转回CAS服务端登录页,证明单点登录系统搭建成功。

    044

6 附录:CAS单点登录实现原理详解

045

如图所示,http://dataviz.com(简称dataviz)表示dataviz应用系统,http://3rd-app.com(简称3rd)表示第三方应用系统,http://sso.com(简称sso)表示CAS单点登录系统。上图是3个登录场景,分别是:第一次访问dataviz、第二次访问dataviz以及登录状态下第一次访问3rd。下面详细说明图中每个数字标号做了什么。

6.1 用户第一次访问dataviz

用户第一次访问dataviz的流程如下:

  1. 用户第一次访问dataviz,dataviz验证其是否登录,如果没有登录,则跳转到sso;

  2. 用户未登录,浏览器返回状态码302,然后让浏览器重定向到sso并且通过在url上添加参数service=dataviz,该参数的目的是登录之后要重定向回dataviz,因此需要该参数;

  3. 用户访问sso,sso发现浏览器的cookie中没有TGC(sso根据cookie中的TGC来判断用户是否登录过,是否需要展示登录界面),认为用户未登录,则显示出登录页面,用户输入账号密码进行登录;

  4. 用户登录成功后,sso返回给浏览器302状态码,重定向的地址就是上文提到的service参数对应的值dataviz并且在url上添加参数ticket(只有在sso中登录成功后,sso才会派发一个ticket,该参数被dataviz用来验证用户是否合法),同时在cookie中设置一个TGC,TGC的作用上文已提到;

  5. 用户重新访问dataviz并在url携带参数ticket;

  6. dataviz从url上解析出ticket,然后在后台通过http的方式向sso验证此ticket是否有效;

  7. 验证ticket有效后,dataviz认为用户已登录并在dataviz的session中设置登录状态,并将用户信息等相关资源展现在浏览器上。

6.2 用户第二次访问dataviz

在2.1节中,用户已经访问过一次dataviz并且登录成功了,当第二次访问dataviz的时候发生了什么呢?

  1. 用户重新访问dataviz,因为dataviz在用户第一次登录成功后会在session中保存用户信息,因此dataviz认为用户已登录,不会再向sso发送请求验证;

  2. 用户通过dataviz的权限验证,浏览器正常返回资源。

6.3 用户在登录状态下第一次访问3rd

  1. 用户正在浏览dataviz系统,突然想访问3rd,于是发起了访问3rd的请求;
  2. 3rd接收到请求,发现是用户第一次访问,于是浏览器返回302,让浏览器重定向到sso;
  3. 用户访问sso并在url中携带service=3rd,在cookie中携带TGC;
  4. sso发现用户请求的时候在cookie中携带了TGC,通过验证TGC确认该用户已登录,便使浏览器返回302状态码,重定向回3rd,并在url中携带sso生成的一个ticket;
  5. 浏览器重定向到3rd并在url携带参数ticket;
  6. 3rd解析出url中的参数ticket,然后在后台通过http的方式向sso验证此ticket是否有效;
  7. 验证ticket有效后,3rd认为用户已登录并在3rd的session中设置登录状态,并将用户信息等相关资源展现在浏览器上。

results matching ""

    No results matching ""

    results matching ""

      No results matching ""