美文网首页
13. Shiro整合CAS

13. Shiro整合CAS

作者: 不知名的蛋挞 | 来源:发表于2019-08-26 10:36 被阅读0次

    Shiro整合CAS

    shiro是现在最为流行的权限认证管理框架,但是现在已经不再是最为传统的shiro处理处理了,因此此时的处理牵扯到了CAS实现认证的操作部分,所以对于shiro而言,它依然需要实现认证与授权检测,但是这个时候的认证应该交由CAS完成。

    在现实的开发过程中,客户端是不可能直接访问CAS服务器的。WEB客户端其实就是CAS客户端,CAS客户端如果想和CAS服务器正常通讯,它就必须有一个证书。所以在整个处理流程里面就首先要有一个证书的操作配置。这个证书配置在JDK上,所以这个CAS客户端必须运行好配置好证书的JDK上。

    我们这次测试模拟 web浏览器——>web服务器(CAS客户端)CAS客户端——>CAS服务器 使用的协议不一样,一个是http,一个是https。因为现在两边的协议不一样,你在整个过程中还需要对CAS服务器进行一次变革,才能让它支持HTTP的协议跳板。

    (1)整合前准备

    1. 需要在本地的windows系统的JDK里面导入服务器端证书

    • 前提:已经准确地配置了JAVA_HOME环境属性
    • 服务器端证书的所在路径:D:\server.cer
    • 认证授权库:JAVA_HOME\jre\lib\security\cacerts
    keytool -import -alias server -file d:\server.cer -keystore "%JAVA_HOME\jre\lib\security\cacerts%" -storepass changeit
    
    • 列出全部的本地的密钥库:
    keytool -list -keystore "%JAVA_HOME\jre\lib\security\cacerts%" -storepass changeit
    

    搜索一下是否有cas.com

    2. 修改cas的配置文件,让其支持http协议访问

    vim /usr/local/tomcat/webapps/cas/WEB-INF/classes/services/HTTPSandIMAPS-10000001.json
    
    默认只支持https 追加支持http

    然后重新启动服务器。那么此时将支持协议访问的路径。

    (2)实现CasRealm

    2.1 导入shiro与cas整合的处理包开发包

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

    2.2 修改数据库脚本

    当前使用的数据表需要包含有角色、权限等信息

    2.3 此时所有的查询内容都将交由CAS负责,而shiro只是负责角色与权限数据的获取

    范例:定义一个MemberCasRealm程序类,需要继承CasRealm父类。

    • 所有的处理都应该交由CAS负责完成,所以此时实际上的认证处理相当于接收CAS认证后的结果(票根);
    • doGetAuthenticationInfo方法:此时接收的AuthenticationToken对象实际上是CasToken类型
    public class MemberCasRealm extends CasRealm {
    
        @Autowired
        private MemberService memberService;
    
        /**
         * 用户身份认证
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            // 此时接收的AuthenticationToken对象实际上是CasToken类型
            CasToken casToken = (CasToken)token;  // 现在需要返回的是CAS认证标记
            if(casToken==null){   // 如果现在没有返回token标记
                return null;  // 当前的登录失败
            }
    
            // CAS一定要返回给用户一个票根,所以需要取得这个票根的内容
            String ticket = (String)casToken.getCredentials();
            // 需要对票根的有效性进行验证
            if(!StringUtils.hasText(ticket)){  // 票根验证失败
                return null;  // 当前的登录失败
            }
    
            // 如果现在票根验证的格式正确,那么需要进行票根的有效性验证
            TicketValidator ticketValidator = super.ensureTicketValidator();
    
            try {
                // 首先需要针对于票根的CAS做一个验证处理
                Assertion casAssertion = ticketValidator.validate(ticket,super.getCasService());
                // 当验证处理完成之后,应该通过CAS取得用户信息
                AttributePrincipal casPrincipal = casAssertion.getPrincipal();
                String mid = casPrincipal.getName();  // 取出当前登录的用户名
                // 取出用户名之后需要将所有的相关信息(包括CAS相关信息)一起进行一个列表的创建
                List principals = CollectionUtils.asList(mid,casPrincipal.getAttributes());
                PrincipalCollection principalCollection = new SimplePrincipalCollection();
                return new SimpleAuthenticationInfo(principalCollection,ticket);
            } catch (TicketValidationException e) {
                e.printStackTrace();
            }
            return super.doGetAuthenticationInfo(token);
        }
    
        /**
         * 用户授权
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String userName = (String)principals.getPrimaryPrincipal();
            SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
    
            try {
               Map<String,Object> map = this.memberService.listAuthByMember(userName);
               Set<String> allRoles = (Set<String>)map.get("allRoles");
               Set<String> allActions = (Set<String>)map.get("allActions");
               auth.setRoles(allRoles);
               auth.setStringPermissions(allActions);
            } catch (TicketValidationException e) {
                e.printStackTrace();
            }
            return auth;
        }
    }
    

    此时对于使用的Realm只有用户认证部分发生了变化,而角色和权限的操作依然像之前那样直接通过业务层读取完成。

    (3)环境配置

    3.1 修改database.propeties文件

    db.driver=org.ght.mm.mysql.Driver
    db.url=jdbc:mysql://192.168.122.204:3306/shriodb
    db.user=root
    db.password=root
    

    3.2 修改spring-shiro.xml文件

    修改当前的Realm使用类型

    <!-- 配置Realm -->
    <bean id="memberRealm" class="com.web.cas.MemberCasRealm"/>
    

    3.3 配置CAS的访问路径

    <!-- 配置Realm -->
    <bean id="memberRealm" class="com.web.cas.MemberCasRealm">
         <!--配置cas服务器的地址-->
         <property name="casServerUrlPrefix" value="https://cas.com"/>
         <!-- 客户端的回调地址设置,必须和下面的shiro-cas过滤器拦截的地址一致 -->
         <property name="casService" value="http://shiro.com/shirodemo/shiro-cas"/>
    </bean>
    

    3.4 配置CAS的访问过滤器

    service=cas客户端回调地址

    <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
            <!-- 登录失败后的访问路径,应该设置为cas.com访问 -->
            <property name="failureUrl" value="https://cas.com/login/service=http://shiro.com/shirodemo/shiro-cas"/>
    </bean>
    

    3.5 配置CAS注销的访问过滤器

    注销就不能再回到回调页面了(总不能注销了再回来吧),所以我们重定向到首页。

    <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
            <property name="redirectUrl" value="https://cas.com/logout?service=http://shiro.com/shirodemo/index.jsp"/>
    </bean>
    

    3.6 修改shiro过滤器

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <!--出现错误之后的跳转路径的配置-->
            <property name="loginUrl" value="https://cas.com/logout?service=http://shiro.com/shirodemo/shiro-cas"/>
            <!--认证失败之后的跳转路径页面-->
            <property name="unauthorizedUrl" value="/unauthUrl.action"/>
            <!--登录成功之后的跳转访问路径-->
            <property name="successUrl" value="/hello.action"/>
            <property name="filters">
                <map>
                    <entry key="casFilter" value-ref="casFilter"/>
                    <entry key="logoutFilter" value-ref="logout"/>
                </map>
            </property>
            <property name="filterChainDefinitions">
                <value>
                    /shiro-cas = casFilter
                    /loginUrl.action=authc
                    /*=anon
                    /message/**=authc
                </value>
            </property>
        </bean>
    

    3.7 修改hosts文件

    所有的访问都是以域名的方式出现的,所以还需要修改hosts文件,追加域名

    127.0.0.1 shiro.com
    

    (4)测试

    访问shiro.com的首页

    输入用户名和密码,从控制台可以看到已经进行了登陆的认证:

    登录之后访问需要授权的页面,后台会出现角色和权限的信息查询提示信息。

    CAS配置Remember me

    如果要想配置rememberMe的操作需要考虑到两个配置部分:shiro(客户端)、cas(认证端)

    1. 修改applicationContext.xml文件,为其追加一个工厂类

    <bean id="securityManager" class="com.vip.vpao.web.cas.VpaoVisSecurityManager">
            <property name="subjectFactory" ref="sSubjectFactory"/>
            <!--其他配置省略-->
        </bean>
    
    <!-- 如果要实现cas的remember me的功能,需要用到下面这个bean,并设置到securityManager的subjectFactory中 -->
    <bean id="subjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>
    

    2. 修改deployerConfigContext.xml配置文件

    对里面的认证管理器authenticationManager进行配置

    
    <bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
            <constructor-arg>
                <map>
                    <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
                    <!-- <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> -->
                    <entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver"/>
                </map>
            </constructor-arg>
     
            <!-- 添加remember me配置-->
            <property name="authenticationMetaDataPopulators">
               <util:list>
                  <bean class="org.jasig.cas.extension.clearpass.CacheCredentialsMetaDataPopulator"
                        c:credentialCache-ref="encryptedMap" />
               </util:list>
            </property>
            
            <property name="authenticationPolicy">
                <bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
            </property>
    </bean>
    

    3. 修改另外一个页面的配置文件:cas\WEB-INF\webflow\login\login-webflow.xml

    找到viewLoginForm表单,里面加上rememberMe标签:

    <view-state id="viewLoginForm" view="casLoginView" model="credential">
            <binder>
                <binding property="username" />
                <binding property="password" />
                <binding property="captcha" />
                <binding property="rememberMe" />
            </binder>
            <on-entry>
                <set name="viewScope.commandName" value="'credential'" />
            </on-entry>
            <transition on="submit" bind="true" validate="true" to="validatorCaptcha">
                <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credential)" />
            </transition>
    </view-state>
    

    4. 修改“cas\WEB-INF\spring-configuration\ticketExpirationPolicies.xml”文件(票根过期的配置文件)

    替换原有的grantingTicketExpirationPolicy的bean为如下内容:

    <bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.RememberMeDelegatingExpirationPolicy">
       <property name="sessionExpirationPolicy">
        <bean class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy">
               <constructor-arg index="0" value="XXXXXXXX" />
        </bean>
       </property>
       <property name="rememberMeExpirationPolicy">
        <bean class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy">
               <constructor-arg index="0" value="XXXXXXXX" />
        </bean>
       </property>
    </bean>
    

    其实就是修改ticket过期策略。

    5. rememberMe需要找到cookie,所以需要修改“cas\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xml”文件

    在ticketGrantingTicketCookieGenerator的bean中增加 p:rememberMeMaxAge="7200000",设定rememberMe保存的最长时间。

    要注意的是这里的7200000为秒数。并且要注意和上面 ticketExpirationPolicies.xml中设置的保持一致。

    6. 此时对于记住我这个信息实际上还没有提示内容,所以需要修改一个资源文件

    • 文件路径:cas\WEB-INF\classes\messages_zh_CN.properties
    • 添加以下配置

    \u8BB0\u4F4F\u6211是中文“记住我”的转码

    7. 修改页面显示文件

    • 文件路径:cas\WEB-INF\view\jsp\default\ui\casLoginView.jsp

    8. 测试

    相关文章

      网友评论

          本文标题:13. Shiro整合CAS

          本文链接:https://www.haomeiwen.com/subject/tlzhsctx.html