• 单点登录(SSO)解决方案之 CAS客户端与Spring Security集成


    接上篇:单点登录(SSO)解决方案之 CAS服务端数据源设置及页面改造

    Spring Security

      Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

    为什么使用CAS集成Spring Security?

      首先我们要明白,一个系统都需要有认证和授权的过程:

        所谓认证,就是当用户试图进入系统,而系统发现用户没有登陆,就调转到登陆页面,然后用户输入用户名,密码,点击登陆按钮,系统进行用户名,密码的校验过程,称之为认证。
        所谓授权,指的是系统对用户名,密码进行认证通过,然后对该用户赋权限,即该用户能够访问这个系统的哪些功能(即该用户能够访问这个系统的哪些url地址及按钮)。

      Spring Security本身是具有认证功能的,但是我们使用CAS做单点登录就相当于把认证这一部分放在了CAS上,也就是说我们使用CAS做认证。

      我们大部分的系统都会有用户、角色以及权限表,我们在CAS做过认证以后使用Spring Security进行授权,也就是认证过的用户取出该用户的权限,根据权限来控制该用户能访问哪些页面等。

    CAS客户端与Spring Security集成Demo:

    1,搭建客户端casclient_demo3,引入spring依赖和spring secrity 相关依赖 ,tomcat端口设置为9003

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>project_demo</artifactId>
            <groupId>com.zy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>casclient_demo3</artifactId>
        <packaging>war</packaging>
    
        <properties>
            <spring.version>4.2.4.RELEASE</spring.version>
        </properties>
    
        <dependencies>
            <!--spring-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <!--security-->
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-web</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-config</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
    
            <!--servlet-->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
                <scope>provided</scope>
            </dependency>
    
            <!--spring和cas集成需要的两个jar包-->
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-cas</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.jasig.cas.client</groupId>
                <artifactId>cas-client-core</artifactId>
                <version>3.3.3</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>log4j-over-slf4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
        </dependencies>
        <build>
            <plugins>
                <!-- java编译插件 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <configuration>
                        <!-- 指定端口 -->
                        <port>9003</port>
                        <!-- 请求路径 -->
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

    2,修改web.xml ,添加过滤器等配置

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-security.xml</param-value>
        </context-param>
        <listener>
            <listener-class>
                org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
    
        <!--security过滤器链-->
        <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
        <!--springMVC DispatcherServlet-->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    </web-app>

    3,创建配置文件springmvc.xml及spring-security.xml

    resources/springmvc.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:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.zy.demo.controller"/>
    
        <mvc:annotation-driven/>
    
    </beans>

    resources/spring-security.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
    
    
        <!--拦截规则  entry-point-ref为入口点引用 use-expressions默认是true -->
        <http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
            <!--允许匿名访问的连接地址-->
            <intercept-url pattern="/public/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"></intercept-url>
            <!-- /* 当前级别目标 子目录是不拦截-->
            <!--如果是ROLE_ADMIN则不拦截admin文件夹下的-->
            <intercept-url pattern="/admin/**" access="ROLE_ADMIN"></intercept-url>
            <!--如果是ROLE_LEADER则不拦截leader文件夹下的-->
            <intercept-url pattern="/leader/**" access="ROLE_LEADER"></intercept-url>
            <!--如果两个角色都有 所有的都不拦截-->
            <intercept-url pattern="/**" access="ROLE_ADMIN,ROLE_LEADER"></intercept-url>
            <!--关闭防CSRF攻击-->
            <csrf disabled="true"></csrf>
    
            <!--配置认证过滤器-->
            <!-- custom-filter为过滤器, position 表示将过滤器放在指定的位置上, before表示放在指定位置之前, after表示放在指定的位置之后  -->
            <custom-filter ref="casAuthenticationFilter" position="CAS_FILTER"/>
            <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
            <custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
        </http>
    
    
        <!-- CAS入口点 开始 -->
        <!--入口点的引用-->
        <beans:bean id="casProcessingFilterEntryPoint"
                    class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
            <!-- 单点登录服务器登录URL -->
            <!--<beans:property name="loginUrl" value="http://localhost:9100/cas/login"/>-->
            <beans:property name="loginUrl" value="http://192.168.44.31:9100/cas/login"/>
            <beans:property name="serviceProperties" ref="serviceProperties"/>
        </beans:bean>
    
        <beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
            <!--service 配置自身工程的根地址+/login/cas   -->
            <beans:property name="service" value="http://localhost:9003/login/cas"/>
        </beans:bean>
        <!-- CAS入口点 结束 -->
    
    
        <!-- 认证过滤器 开始 -->
        <beans:bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
            <beans:property name="authenticationManager" ref="authenticationManager"/>
        </beans:bean>
    
        <!-- 认证管理器 -->
        <authentication-manager alias="authenticationManager">
            <authentication-provider ref="casAuthenticationProvider">
            </authentication-provider>
        </authentication-manager>
    
        <!-- 认证提供者 -->
        <beans:bean id="casAuthenticationProvider"
                    class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
            <beans:property name="authenticationUserDetailsService">
                <beans:bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                    <beans:constructor-arg ref="userDetailsService"/>
                </beans:bean>
            </beans:property>
            <beans:property name="serviceProperties" ref="serviceProperties"/>
            <!-- ticketValidator 为票据验证器 -->
            <beans:property name="ticketValidator">
                <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                    <!--<beans:constructor-arg index="0" value="http://localhost:9100/cas"/>-->
                    <beans:constructor-arg index="0" value="http://192.168.44.31:9100/cas"/>
                </beans:bean>
            </beans:property>
            <beans:property name="key" value="an_id_for_this_auth_provider_only"/>
        </beans:bean>
    
        <!--获取授权信息的bean-->
        <!-- 认证类 -->
        <beans:bean id="userDetailsService" class="com.zy.demo.service.UserDetailsServiceImpl"/>
        <!-- 认证过滤器 结束 -->
    
    
        <!--退出的过滤器-->
        <!-- 单点登出  开始  -->
        <beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
        <beans:bean id="requestSingleLogoutFilter"
                    class="org.springframework.security.web.authentication.logout.LogoutFilter">
            <!--退出登录后跳转到百度-->
            <!--<beans:constructor-arg value="http://localhost:9100/cas/logout?service=http://www.baidu.com"/>-->
            <beans:constructor-arg value="http://192.168.44.31:9100/cas/logout?service=http://www.baidu.com"/>
            <beans:constructor-arg>
                <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
            </beans:constructor-arg>
            <beans:property name="filterProcessesUrl" value="/logout/cas"/>
        </beans:bean>
        <!-- 单点登出  结束 -->
    </beans:beans>

    4,编写认证类java.com.zy.demo.controller.service.UserDetailsServiceImpl  需要实现UserDetailsService接口

    package com.zy.demo.service;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 使用security控制权限
     */
    @Component
    public class UserDetailsServiceImpl implements UserDetailsService {
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            //可以根据用户名取数据库取出来权限
            String authorityLeader = "ROLE_LEADER";
            String authorityAdmin = "ROLE_ADMIN";
    
            //然后授权
            List<GrantedAuthority> authorityList = new ArrayList<>();//权限列表
            //GrantedAuthority authority = new SimpleGrantedAuthority(authorityLeader);//权限
            authorityList.add(new SimpleGrantedAuthority(authorityLeader));
            //authorityList.add(new SimpleGrantedAuthority(authorityAdmin));
    
            System.out.println("对用户进行授权");
            return new User(username, "", authorityList);
        }
    }

    5,添加测试html页面

    在webapp下新建leader和admin两个文件夹,并在文件夹内分别新建index.jsp页面(当前页可以建其他页面,此处主要用来演示权限限制):

    webapp/admin/index.jsp

    <%@ page language="java" contentType="text/html; charset=utf-8"
             pageEncoding="utf-8" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>
    <h1>admin页面</h1>
    <%=request.getRemoteUser()%>
    <br/>
    <a href="/logout/cas">单点退出</a>
    </body>
    </html>

    webapp/leader/index.jsp

    <%@ page language="java" contentType="text/html; charset=utf-8"
             pageEncoding="utf-8" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>
    <h1>leader页面</h1>
    <%=request.getRemoteUser()%>
    <br/>
    <a href="/logout/cas">单点退出</a>
    </body>
    </html>

    以上工程搭建完成。

    启动项目,浏览器输入localhost:9003/leader/index.jsp,登录后:

    浏览器输入localhost:9003/admin/index.jsp:

    拒绝访问,因为我们在UserDetailsServiceImpl 只给用户赋予了ROLE_LEADER的权限。

    以上。

    后续补充:Demo及所需资料百度云地址:链接:https://pan.baidu.com/s/1Dr4Aq9-FWGnL3kRCZ3uwVA 密码:0i30

  • 相关阅读:
    java 基础笔记 基本数据类型对象包装类
    java String 类 基础笔记
    java 线程 笔记 基础
    java 线程 基础笔记2
    java 异常学习 笔记
    广告简单概念整理-持续更新
    curl一些使用技巧
    简单学习正则表达式
    Linux命令简单操作之lsof
    Linux命令简单操作之find和xargs
  • 原文地址:https://www.cnblogs.com/blazeZzz/p/9581949.html
Copyright © 2020-2023  润新知