《跟我学Shiro》笔记15-单点登录

  1. 服务器端
  2. 客户端

原文地址:第十五章 单点登录——《跟我学Shiro》
目录贴: 跟我学Shiro目录贴
源码:https://github.com/zhangkaitao/shiro-example

Shiro 1.2 开始提供了 Jasig CAS 单点登录的支持,单点登录主要用于多系统集成,即在多个系统中,用户只需要到一个中央服务器登录一次即可访问这些系统中的任何一个,无须多次登录。此处我们使用 Jasig CAS v4.0.0-RC3 版本

Jasig CAS 单点登录系统分为服务器端和客户端,服务器端提供单点登录,多个客户端(子系统)将跳转到该服务器进行登录验证,大体流程如下:

  1. 访问客户端需要登录的页面 http://localhost:9080/client/,此时会跳到单点登录服务器 https://localhost:8443/server/login?service=https://localhost:9443/client/cas;
  2. 如果此时单点登录服务器也没有登录的话,会显示登录表单页面,输入用户名/密码进行登录;
  3. 登录成功后服务器端会回调客户端传入的地址:https://localhost:9443/client/cas?ticket=ST-1-eh2cIo92F9syvoMs5DOg-cas01.example.org,且带着一个 ticket
  4. 客户端会把 ticket 提交给服务器来验证 ticket 是否有效;如果有效服务器端将返回用户身份;
  5. 客户端可以再根据这个用户身份获取如当前系统用户/角色/权限信息。

服务器端

我们使用了 Jasig CAS 服务器 v4.0.0-RC3 版本,可以到其官方的 github 下载:https://github.com/Jasig/cas/tree/v4.0.0-RC3 下载,然后将其 cas-server-webapp 模块封装到 shiro-example-chapter15-server 模块中,具体请参考源码。

修改 src/main/webapp/WEB-INF/deployerConfigContext.xml,找到 primaryAuthenticationHandler,然后添加一个账户: <entry key="zhang" value="123"/>,其也支持如 JDBC 查询,可以自己定制;具体请参考文档。

客户端

首先使用 localhost.keystore 导出数字证书(公钥)到 D:\localhost.cer

keytool -export -alias localhost -file D:\localhost.cer -keystore D:\localhost.keystore

因为 CAS client 需要使用该证书进行验证,需要将证书导入到 JDK 中:

cd D:\jdk1.7.0_21\jre\lib\security
keytool -import -alias localhost -file D:\localhost.cer -noprompt -trustcacerts -storetype jks -keystore cacerts -storepass 123456

导入 shiro-cas 依赖:

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-cas</artifactId>
    <version>1.2.2</version>
</dependency>

自定义 CasRealm

// CasRealm 根据 CAS 服务器端返回的用户身份获取相应的角色/权限信息。
public class MyCasRealm extends CasRealm {

    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String)principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.findRoles(username));
        authorizationInfo.setStringPermissions(userService.findPermissions(username));

        return authorizationInfo;
    }
}

spring-shiro-web.xml 配置:

<bean id="casRealm" class="com.github.zhangkaitao.shiro.chapter13.realm.MyCasRealm">
    <property name="userService" ref="userService"/>
    <!-- …… -->
    <property name="casServerUrlPrefix" value="https://localhost:8443/chapter15-server"/>
    <property name="casService" value="https://localhost:9443/chapter15-client/cas"/>
</bean>
  • casServerUrlPrefix:是 CAS Server 服务器端地址;
  • casService:是当前应用 CAS 服务 URL,即用于接收并处理登录成功后的 Ticket 的;

如果角色/权限信息是由服务器端提供的话,我们可以直接使用 CasRealm

<bean id="casRealm" class="org.apache.shiro.cas.CasRealm">
    <!-- …… -->
    <property name="defaultRoles" value="admin,user"/>
    <property name="defaultPermissions" value="user:create,user:update"/>
    <property name="roleAttributeNames" value="roles"/>
    <property name="permissionAttributeNames" value="permissions"/>
    <property name="casServerUrlPrefix" value="https://localhost:8443/chapter15-server"/>
    <property name="casService" value="https://localhost:9443/chapter15-client/cas"/>
</bean>
  • defaultRoles/defaultPermissions:默认添加给所有 CAS 登录成功用户的角色和权限信息;
  • roleAttributeNames/permissionAttributeNames:角色属性/权限属性名称,如果用户的角色/权限信息是从服务器端返回的(即返回的 CAS Principal 中除了 Principal 之外还有如一些 Attributes),此时可以使用 roleAttributeNames/permissionAttributeNames 得到 Attributes 中的角色/权限数据;请自行查询 CAS 获取用户更多信息。
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
    <property name="failureUrl" value="/casFailure.jsp"/>
</bean>

CasFilter 类似于 FormAuthenticationFilter,只不过其验证服务器端返回的 CAS Service Ticket

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="https://localhost:8443/chapter15-server/login?service=https://localhost:9443/chapter15-client/cas"/>
    <property name="successUrl" value="/"/>
    <property name="filters">
        <util:map>
            <entry key="cas" value-ref="casFilter"/>
        </util:map>
    </property>
    <property name="filterChainDefinitions">
        <value>
            /casFailure.jsp = anon
            /cas = cas
            /logout = logout
            /** = user
        </value>
    </property>
</bean>
  • loginUrlhttps://localhost:8443/chapter15-server/login 表示服务端端登录地址,登录成功后跳转到 ?service 参数对于的地址进行客户端验证及登录;
  • /cas=cas:即 /cas 地址是服务器端回调地址,使用 CasFilter 获取 Ticket 进行登录。

第十六章 综合实例
第十七章 OAuth2集成


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:《跟我学Shiro》笔记15-单点登录

文章字数:1.3k

本文作者:Bin

发布时间:2018-04-20, 20:12:22

最后更新:2019-09-03, 16:50:26

原始链接:http://coolview.github.io/2018/04/20/%E8%B7%9F%E6%88%91%E5%AD%A6Shiro/%E3%80%8A%E8%B7%9F%E6%88%91%E5%AD%A6Shiro%E3%80%8B%E7%AC%94%E8%AE%B015-%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录