springMVC集成shiro与cas实现SSO单点登录

一、前言

Apache Shiro与Spring Security一样是Java的一个安全框架。那为什么与Spring整合却用Shiro?其实我个人是认为Spring Security太过于笨重,要写太多的过滤器,Shiro的配置简单这就是我选择的理由,何况Spring官方自己都推荐使用Shiro。Shiro最主要的就是认证与授权,而CAS的重点在于单点登录,其实CAS与Shiro整合的话就是关于认证那块的整合。

二、配置

第一步、添加Maven依赖

        <!-- shiro依赖包 -->
        <dependency>
          <groupId>org.apache.shiro</groupId>
          <artifactId>shiro-core</artifactId>
          <version>1.2.4</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        
        <!-- shiro-cas集成依赖包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-cas</artifactId>
            <version>1.2.3</version>
        </dependency>
第二步、web.xml中添加shiro过滤器

    <!-- 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>
第三步、添加applicationContext-shiro.xml配置文件

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="  
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">

    <description>Shiro 配置</description>

    <!-- CasFilter为自定义的单点登录Fileter -->
   <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
        <!--  配置验证错误时的失败页面 -->
        <property name="failureUrl" value="/static/no-permission.jsp"/>
    </bean> 
    
    <!--shiroFilter的bean Name必须与web.xml中shiro filter的名字一致-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->  
        <property name="securityManager" ref="securityManager"/>
        <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 --> 
        <property name="loginUrl" value="http://cas.uat.qa.nt.ctripcorp.com/caso/login?service=http://127.0.0.1:8080/springdemo/shiro-cas"/>
        <property name="successUrl" value="/"/>
        <!-- 用户访问未对其授权的资源时,所显示的连接 -->
        <property name="unauthorizedUrl" value="/static/no-permission.jsp"/>
        
        <!-- The 'filters' property is usually not necessary unless performing 
            an override, which we want to do here (make authc point to a PassthruAuthenticationFilter 
            instead of the default FormAuthenticationFilter: -->
        <property name="filters">
            <util:map>
                <!-- 添加casFilter到shiroFilter整合 -->
                <entry key="casFilter" value-ref="casFilter"/>
               <!--  <entry key="perms">
                    <bean
                        class="com.lora.shiro.filter.MyPermissionsAuthorizationFilter" />
                </entry>  -->
            </util:map>
        </property>

        <!-- 读取自定义权限内容-->
        <property name="filterChainDefinitions">
            <value>
                /shiro-cas = casFilter
                /addUser/** = authc
                /show/** = authc
                /login = anon
                /toLogin/login = anon
                /static/** = anon
                /static/no-permission.jsp = anon
                /greeting** = authc,perms[admin:manage]
                /** = anon
                <!-- /home* = roles["adminHome"] -->
            </value>
        </property>
    </bean>
     
     <!-- 单点登录下的配置 -->
     <bean id="casRealm" class="com.lora.shiro.MyCasRealm">
        <property name="defaultRoles" value="ROLE_USER"/>
        <!-- cas服务端地址前缀 -->
        <property name="casServerUrlPrefix" value="http://cas.uat.qa.nt.ctripcorp.com/caso" />
        <!-- 应用服务地址,用来接收cas服务端票据 -->
        <!-- 客户端的回调地址设置,必须和上面的shiro-cas过滤器casFilter拦截的地址一致 -->
        <property name="casService" value="http://127.0.0.1:8080/springdemo/shiro-cas" />
    </bean>

    <!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
       <!--  设置自定义realm  ref="iniRealm,mySecurityRealm" -->
        <!-- <property name="realm" ref="myRealm"/> -->
         <property name="realm" ref="casRealm"/>
    </bean>
    
    <!--保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  

    <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
    <bean
        class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod"
            value="org.apache.shiro.SecurityUtils.setSecurityManager" />
        <property name="arguments" ref="securityManager" />
    </bean>

    <!-- 用于开启 Shiro Spring AOP 权限注解的支持 -->
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
        
</beans>  
第四步、 添加自定义realm配置的实现类MyCasRealm

package com.lora.shiro;

import java.util.Iterator;
import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;

import com.lora.model.User;

public class MyCasRealm extends CasRealm {

    /**
     * 授权,获取用户的角色、权限
     */
    @SuppressWarnings("rawtypes")
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("Principal对象不能为空");
        }
        Iterator it = principals.fromRealm(getName()).iterator();
        String username = null;
        if (it.hasNext()) {
            username = (String) it.next();
        } else {
            username = principals.toString();
        }
        //获取用户响应的permission
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if (username != null) {
            // 添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
            info.addRole("admin");
            // 添加权限
            info.addStringPermission("admin:manage");
            System.out.println("已为用户赋予了[admin]角色和[admin:manage]权限");
            return info;
        }
        return info;
    }

    /**
     * 认证,登录验证。
     */
    @SuppressWarnings("rawtypes")
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo authenticationInfo = super
                .doGetAuthenticationInfo(token);
        PrincipalCollection principalCollection = authenticationInfo
                .getPrincipals();
        Map loginDataMap = (Map) principalCollection.asList().get(1);
        String userAccount = (String) loginDataMap.get("name");
        String userCode = (String) loginDataMap.get("employee");
        String fullName = (String) loginDataMap.get("sn");
        String department = (String) loginDataMap.get("department");
        String email = (String) loginDataMap.get("mail");
        User user = new User();
        user.setUserCode(userCode);
        user.setUserAccount(userAccount);
        user.setUname(fullName);
        user.setDepartment(department);
        user.setEmail(email);
        // 将用户保存在SESSION回话中
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("currentUser", user);
        return authenticationInfo;
    }
}

以上步骤完成,shiro集成cas的步骤就完成了,实现了单点登录。





猜你喜欢

转载自blog.csdn.net/wangli61289/article/details/79224943
今日推荐