cas4.2.7与shiro进行整合

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cas4.2.7与shiro进行整合相关的知识,希望对你有一定的参考价值。

准备工作

  cas单点登录开始前准备,请参考cas4.2.7实现单点登录

与shiro进行整合

  注:准备工作的基础上,对cas客户端进行如下改进。

  引入相关jar包

shiro-cas-1.2.6.jar
shiro-core-1.2.6.jar
shiro-spring-1.2.6.jar
shiro-web-1.2.6.jar

  web.xml引入shiro过滤器

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Archetype Created Web Application</display-name>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring-web.xml, classpath:spring-shiro.xml
        </param-value>
    </context-param>

    <!-- Shiro配置 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- ****************** 单点登录开始 ********************-->
    <!-- 用于实现单点登出功能  可选 -->
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!-- 该过滤器用于实现单点登出功能,单点退出配置,一定要放在其他filter之前 可选 -->
    <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>http://127.0.0.1:8080/cas-web/</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 该过滤器对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 HttpServletRequest Wrapper Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
         比如AssertionHolder.getAssertion().getPrincipal().getName()。
         这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 -->
    <filter>
        <filter-name>CAS Assertion Thread Local Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS Assertion Thread Local Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- ****************** 单点登录结束 ********************-->

    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-web.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

  引入shiro的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:shiro.properties" ignore-unresolvable="true"/>

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!-- 设定角色的登录链接,这里为cas登录页面的链接可配置回调地址  -->
        <property name="loginUrl" value="${cas.loginUrl}" />
        <property name="successUrl" value="${shiro.successUrl}" />
        <property name="filters">
            <map>
                <entry key="casFilter" value-ref="casFilter"/>
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /shiro-cas = casFilter
                /** = authc
            </value>
        </property>
    </bean>

    <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
        <property name="failureUrl" value="${shiro.failureUrl}"/>
    </bean>

    <bean id="ShiroCasRealm" class="com.hjzgg.client.shiro.ShiroCasRealm"/>

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="ShiroCasRealm"/>
        <property name="subjectFactory" ref="casSubjectFactory"/>
    </bean>

    <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    </bean>
</beans>

  引入shiro的需要属性

cas.loginUrl=http://127.0.0.1:8080/cas-web/login?service=http://127.0.0.1:8080/cas-client/shiro-cas
cas.logoutUrl=http://127.0.0.1:8080/cas-web/logout?service=http://127.0.0.1:8080/cas-client/shiro-cas
cas.serverUrlPrefix=http://127.0.0.1:8080/cas-web
shiro.cas.service=http://127.0.0.1:8080/cas-client/shiro-cas
shiro.failureUrl=/error
shiro.successUrl=/success

  自定义shiro的realm

package com.hjzgg.client.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasAuthenticationException;
import org.apache.shiro.cas.CasToken;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.util.AssertionHolder;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Value;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ShiroCasRealm extends AuthorizingRealm {

    @Value("${shiro.cas.service}")
    private String shiroCasServiceUrl;

    @Value("${cas.serverUrlPrefix}")
    private String casServerUrlPrefix;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        AttributePrincipal principal = AssertionHolder.getAssertion().getPrincipal();
        if (principal != null) {
            Map<String, Object> attributes = principal.getAttributes();
            if (attributes.size() > 0) {
//                List<String> roles = CommonUtils.arrayStringtoArrayList((String)attributes.get("roles"));
                List<String> roles = null;
                //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                //用户的角色集合      
                info.addRoles(roles);
                //用户的角色对应的所有权限,如果只使用角色定义访问权限,下面的一行可以不要      
                //info.addStringPermissions(user.getPermissionList());
            }
        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        CasToken casToken = (CasToken) token;
        if (token == null)
            return null;
        String ticket = (String) casToken.getCredentials();
        if (!StringUtils.hasText(ticket))
            return null;
        Cas20ServiceTicketValidator cas20ServiceTicketValidator = new Cas20ServiceTicketValidator(casServerUrlPrefix);
        cas20ServiceTicketValidator.setEncoding("utf-8");
        TicketValidator ticketValidator = cas20ServiceTicketValidator;
        try {

            Assertion casAssertion = ticketValidator.validate(ticket, shiroCasServiceUrl);
            AttributePrincipal casPrincipal = casAssertion.getPrincipal();
            String userId = casPrincipal.getName();
            List principals = new ArrayList<String>();
            if (casPrincipal != null) {
                Map<String, Object> attributes = casPrincipal.getAttributes();
                principals.add(userId);
                principals.add(attributes);
            }

            PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, getName());
            return new SimpleAuthenticationInfo(principalCollection, ticket);
        } catch (TicketValidationException e) {
            throw new CasAuthenticationException((new StringBuilder()).append("Unable to validate ticket [").append(ticket).append("]").toString(), e);
        }

    }

    @Override
    protected void onInit() {
        super.onInit();
        this.setAuthenticationTokenClass(CasToken.class);
    }
}

  引入日志系统

    http://www.cnblogs.com/hujunzheng/p/6926429.html

遇到的问题

  shiro+cas学习及整合问题

  cas4.2.7学习笔记

项目地址

  https://github.com/hjzgg/cas4.2.7-authentication/tree/shiro+cas

 

以上是关于cas4.2.7与shiro进行整合的主要内容,如果未能解决你的问题,请参考以下文章

cas4.2.7 集群服务搭建

全栈编程系列SpringBoot整合Shiro(含KickoutSessionControlFilter并发在线人数控制以及不生效问题配置启动异常No SecurityManager...)(代码片段

cas4.2.7 取消https

cas4.2.7实现单点登录

cas4.2.7单点登录带验证码服务端客户端搭建

(转) shiro权限框架详解06-shiro与web项目整合(上)