Skip to content

Latest commit

 

History

History
402 lines (325 loc) · 13.1 KB

客户端.md

File metadata and controls

402 lines (325 loc) · 13.1 KB

客户端

CAS - Architecture (apereo.github.io)

CAS - Multifactor Authentication (apereo.github.io)

cas-projects/cas-sample-java-webapp: Sample Java web app protected by Java CAS client (github.com)

服务端配置

服务注册

application.properties中添加

# 从json文件初始化
cas.serviceRegistry.initFromJson=true
cas.serviceRegistry.watcherEnabled=true
cas.serviceRegistry.schedule.repeatInterval=120000
cas.serviceRegistry.schedule.startDelay=15000
cas.serviceRegistry.managementType=DEFAULT
cas.serviceRegistry.json.location=classpath:/services

json规则

拷贝target/cas/war/WEB-INF/classes/services/HTTPSandIMAPS-10000001.jsonsrc/main/resources/services

支持 http 应用接入

修改src/main/resources/services/HTTPSandIMAPS-10000001.json

serviceId正则表达式中添加http以支持 http 应用接入

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(http|https|imaps)://.*",
  "name" : "HTTP,HTTPS and IMAPS",
  "id" : 10000001,
  "description" : "This service definition authorizes all application urls that support HTTP,HTTPS and IMAPS protocols.",
  "evaluationOrder" : 10000
}
添加接入应用

src/main/resources/services下创建sjzt-10000003.json

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(http|https)://127.0.0.1:\\d*.*",
  "name" : "sjzt",
  "theme" : "apereo",
  "id" : 10000003,
  "description" : "数据中台服务",
  "evaluationOrder" : 1
}

serviceId中正则表达式匹配应用地址,可匹配多个应用

文件命名规则为

JSON fileName = serviceName + "-" + serviceNumericId + ".json"

CAS - Service Management (apereo.github.io)

CAS - JSON Service Registry (apereo.github.io)

pom.xml

<!-- https://mvnrepository.com/artifact/org.jasig.cas.client/cas-client-core -->
<dependency>
    <groupId>org.jasig.cas.client</groupId>
    <artifactId>cas-client-core</artifactId>
    <version>3.6.2</version>
</dependency>

web.xml

<!-- 单点退出 -->
<filter>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
    <init-param>
        <!-- cas服务地址 -->
        <param-name>casServerUrlPrefix</param-name>
        <param-value>http://127.0.0.1:8085/cas</param-value>
    </init-param>
</filter>

<listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

<!-- ticket校验 -->
<filter>
    <filter-name>CAS Validation Filter</filter-name>
    <!--<filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>-->
    <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
    <init-param>
        <!-- cas服务地址 -->
        <param-name>casServerUrlPrefix</param-name>
        <param-value>http://192.168.3.88:8085/cas</param-value>
    </init-param>
    <init-param>
        <!-- 应用地址 -->
        <param-name>serverName</param-name>
        <param-value>http://127.0.0.1:8080</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>
    <!--
        <init-param>
            <param-name>acceptAnyProxy</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>proxyReceptorUrl</param-name>
            <param-value>/sample/proxyUrl</param-value>
        </init-param>
        <init-param>
            <param-name>proxyCallbackUrl</param-name>
            <param-value>https://mmoayyed.unicon.net:9443/sample/proxyUrl</param-value>
        </init-param>
        -->
    <init-param>
        <param-name>authn_method</param-name>
        <param-value>mfa-duo</param-value>
    </init-param>
</filter>

<!-- 登录跳转 -->
<filter>
    <filter-name>CAS Authentication Filter</filter-name>
    <!--<filter-class>org.jasig.cas.client.authentication.Saml11AuthenticationFilter</filter-class>-->
    <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    <init-param>
        <!-- cas登录地址 -->
        <param-name>casServerLoginUrl</param-name>
        <param-value>http://192.168.3.88:8085/cas/login</param-value>
    </init-param>
    <init-param>
        <!-- 应用地址,登录成功后会跳回这个地址+跳转前的路径 -->
        <param-name>serverName</param-name>
        <param-value>http://127.0.0.1:8080</param-value>
    </init-param>
</filter>

<!-- HttpServletRequest包裹,可通过HttpServletRequest.getRemoteUser()获取登录人账号 -->
<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>/casClient/login</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>CAS Authentication Filter</filter-name>
    <url-pattern>/casClient/login</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

为实现单向的单点登录,即可不通过单点登录进入系统,cas 拦截器仅拦截了/casClient/login一个路径,因此应用系统需要拦截未登录时跳转到/casClient/login配合 cas 拦截器实现 ticket校验、单点登录跳转

SSO单点登录系列6:cas单点登录防止登出退出后刷新后退ticket失效报500错_落雨-CSDN博客

CAS 5.2.x 单点登录 - 搭建服务端和客户端 - 简书 (jianshu.com)

cas5.3.2单点登录-集成客户端(六)_这个名字想了很久-CSDN博客

Spring + shiro 接入

shiro 拦截配置

放行/casClient/**,未登录跳转/casClient/login,即由/casClient/login处理单点登录、应用内登录

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 未登录跳转 -->
    <property name="loginUrl" value="/casClient/login" />
    <property name="filterChainDefinitions">
        <value>
            /=anon
            /casClient/**=anon
            /**=authc
        </value>
    </property>
</bean>

/casClient/login

@RequestMapping("/login")
public ModelAndView index(ModelAndView modelAndView, HttpServletRequest request) {
    // 已登陆跳转
    User user = getUser();
    if(user != null) {
        return new ModelAndView("redirect:/space");
    }

    // 获取单点登录用户
    String phone = request.getRemoteUser();
    if (StringUtil.isNotEmpty(phone)) {
        // remoteUser
        User casUser = userService.selectOne(new EntityWrapper<User>().eq("phone", phone));
        if (null != casUser) {
            // 用户存在开始登录
            Subject subject = SecurityUtils.getSubject();
            //					SecurityUtils.getSecurityManager().logout(subject);
            // 登录后存放进shiro token
            UsernamePasswordToken token = new UsernamePasswordToken(casUser.getUserNo(), casUser.getPassword());
            token.setHost("2");
            try {
                subject.login(token);
                return new ModelAndView("redirect:/space");
            } catch (AuthenticationException e) {

            }
        }
    }

    return new ModelAndView("redirect:/login");
}

认证逻辑

进入任一应用地址

  • shiro 拦截应用地址
    • 已登录正常进入
    • 未登录跳转/casClient/login
      • shiro 放行/casClient/login
        • cas 拦截/casClient/login鉴权
          • cas 已登录,从 cas 包裹的HttpServletRequest取出 remote user,完成 shiro 登录逻辑,跳转首页[1]
          • cas 未登录,跳转单点登录页面
            • cas 登录成功,跳回/casClient/login
              • [1]

[1]处可使用WebUtils.getSavedRequest(HttpServletRequest)取出被拦截的应用地址,在完成 shiro 登录逻辑之后跳回应用地址

SavedRequest savedRequest = WebUtils.getSavedRequest(request);
if(savedRequest != null) {
    String savedUrl = savedRequest.getRequestUrl();
    if(StringUtil.isNotEmpty(savedUrl)) {
        return new ModelAndView("redirect:" + savedUrl);
    } else {
        return new ModelAndView("redirect:/space");
    }
}

单向认证

因 cas 只拦截/casClient/login,单向认证逻辑与普通 shiro 一致,只需 shiro 放行应用内登录地址,在该地址登录即可

/casClient/single

@RequestMapping("/single")
public ModelAndView single(ModelAndView modelAndView) {
    User user = getUser();
    if(user == null) {
        modelAndView.setViewName("/home/login");
        return modelAndView;
    }else {
        return new ModelAndView("redirect:/space");
    }
}

登出

application.properties中添加

# 允许登出后重定向
cas.logout.followServiceRedirects=true
# 重定向地址的参数名称
cas.logout.redirectParameter=service
# 重定向地址,配置该参数redirectParameter失效
#cas.logout.redirectUrl=http://www.github.com
# 登出是否提示
cas.logout.confirmLogout=false
# 移除子系统票据
cas.logout.removeDescendantTickets=true

CAS Properties (apereo.github.io)

protected ModelAndView handleRequestInternal(  
     final HttpServletRequest request, final HttpServletResponse response)  
     throws Exception {  
    //取得TGT_ID  
     final String ticketGrantingTicketId = this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request);  
     // 取得service参数数据,这个参数是可选参数  
     final String service = request.getParameter("service");  

     //如果TGT不为空  
     if (ticketGrantingTicketId != null) {  
        //那么在centralAuthenticationService中销毁  
         this.centralAuthenticationService  
             .destroyTicketGrantingTicket(ticketGrantingTicketId);  
         //ticketGrantingTicketCookieGenerator 中销毁cookie  
         this.ticketGrantingTicketCookieGenerator.removeCookie(response);  
         //warnCookieGenerator 中销毁  
         this.warnCookieGenerator.removeCookie(response);  
     }  
     // 如果参数:followServiceRedirects为true 同时service不会空的时候,跳转到service指定的URL  
     if (this.followServiceRedirects && service != null) {  
         return new ModelAndView(new RedirectView(service));  
     }  
     //否则,跳转到logoutView指定的页面  
     return new ModelAndView(this.logoutView);  
}

cas单点登录-单点登出(十一)_weixin_42073629的博客-CSDN博客_单点登出

退出时可重定向

http://127.0.0.1:8085/cas/logout?service=http://www.baidu.com

登出回到应用登录地址

http://127.0.0.1:8085/cas/logout?service=http://127.0.0.1:8080/casClient/login

单点登出

单点登出默认开启

关闭单点登出,在application.properties中添加

# 关闭单点登出
cas.slo.disabled=false
cas.slo.asynchronous=true

疑难问题

javax.servlet.ServletException: org.jasig.cas.client.validation.TicketValidationException: 鏈兘澶熻瘑鍒嚭鐩爣 'ST-41-2VcnVMguCDWJX5zHaaaD-cas01.example.org'绁ㄦ牴

web.xml拦截器应用地址未配置正确

未认证授权的服务,CAS 的服务记录是空的

没有配置应用的 json 服务或者 json 中serviceId地址匹配不对

CAS 5.2.x 单点登录 - 搭建服务端和客户端 - 简书 (jianshu.com)

未认证授权的服务,不允许xxx

json 没有配置允许 http 接入

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching idcardcert.market.alicloudapi.com found.

服务端使用了自签名的 ssl 证书

SSL证书认证失败javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: 解决方法_二月如若微风的博客-CSDN博客