Spring Security 源码分析八:Spring Security 过滤链二 - Demo 例子

栏目: 后端 · 发布时间: 4年前

内容简介:本文是对 Spring Security Core 4.0.4 Release 进行源码分析的系列文章之一;本文为作者的原创作品,转载需注明出处;本章,笔者将试图通过一个 Spring Security 的 Demo 来简单描述一下 Spring Security 过滤链是如何工作的;该例子中将会分别创建两个SecurityFilterChain,一个是

本文是对 Spring Security Core 4.0.4 Release 进行源码分析的系列文章之一;

本文为作者的原创作品,转载需注明出处;

简介

本章,笔者将试图通过一个 Spring Security 的 Demo 来简单描述一下 Spring Security 过滤链是如何工作的;该例子中将会分别创建两个SecurityFilterChain,一个是 /web/** ,一个是 /rest/** 的过滤链;

Demo

该 Demo 是基于 Spring Boot Web Security 所构建而来;根据当前项目需要,版本稍低 1.3.8.RELEASE;

POM

<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">
   
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.shangyang.spring</groupId>
   <artifactId>security-demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   
    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.8.RELEASE</version>
    </parent>

    <!-- Add typical dependencies for a web application -->
    <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>      
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-devtools</artifactId>
           <optional>true</optional>
       </dependency>        
    </dependencies>

   <properties>
       <java.version>1.8</java.version>
   </properties>

    <!-- Package as an executable jar -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>  
</project>

DemoApplication

@Controller
@EnableAutoConfiguration
public class DemoApplication {

   ...
    
    @Configuration
    @EnableWebSecurity
    @Order(1)
    static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      
      @Autowired
      public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
         
         auth
            .inMemoryAuthentication()
               .withUser("user").password("password").roles("USER").and()  
               .withUser("manager").password("password").roles("MANAGER");
         
      }
      
        @Override
        protected void configure(HttpSecurity http) throws Exception {
         
            http.antMatcher("/web/**") // the filter chain defined for web request
               .authorizeRequests()
               .antMatchers("/web/report/**").hasRole("MANAGER")
               .anyRequest().authenticated()
               .and()
               .formLogin()
                  // login 的相对路径必须与 security chain 的的相对路径吻合,这里是 /web/**;注意 login 分两步,一步是 Getter 会到 login.html,另外一步是从 login.html -> post -> /web/login/
                  .loginPage("/web/login")
                  // 允许访问
                  .permitAll(); 
            
        }
    }
    
    @Configuration
    @EnableWebSecurity
    @Order(2)
    static class RestSecurityConfig extends WebSecurityConfigurerAdapter {
      
        @Override
        protected void configure(HttpSecurity http) throws Exception {
         
            http.antMatcher("/rest/**") // the filter chain defined for web request;
               .csrf().disable() // rest 请求无需 CSRF Token;
               .authorizeRequests()
                  .antMatchers("/rest/hello").hasRole("USER")
                  .anyRequest().authenticated()
               .and()
                  .httpBasic();
            
        }
    }    
    
    public static void main(String[] args) throws Exception {
      
        SpringApplication.run(DemoApplication.class, args);
    }
   
}

通过 WebSecurityConfigurerAdapter 配置实现了两个 Spring Security 过滤链,一个是 /web/** ,一个是 /rest/** 的过滤链;从名称上可以清晰的看到,一个过滤链是用来处理 web request ,另外一个过滤链用来处理 restful request

  • web request 过滤链

    使用 Form Login 的方式进行登录验证;

    用户需要由 MANAGER 角色才能访问相关资源;

    使用 CSRF token filter 进行验证;

    ……

  • restful request 过滤链

    使用 Basic Auth 的方式进行登录验证;

    用户需要由 USER 角色才能访问相关资源;

    不使用 CSRF token filter 进行验证;

    ……

Web 登录

Spring Security 源码分析八:Spring Security 过滤链二 - Demo 例子

走 login form 的流程,针对该流程,Spring Security 会提供基于 URL /web/login/ 的 post 请求的方法,用来验证用户基于表单的认证请求;

login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" class="uk-height-1-1">
<head>
    <meta charset="UTF-8"/>
    <title>OAuth2 SSO Demo</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.26.3/css/uikit.gradient.min.css"/>
</head>

<body class="uk-height-1-1">

<div class="uk-vertical-align uk-text-center uk-height-1-1">
    <div class="uk-vertical-align-middle" style="width: 250px;">
        <h1>Login Form</h1>

        <p class="uk-text-danger" th:if="${param.error}">
            Login failed ...
        </p>

        <p class="uk-text-success" th:if="${param.logout}">
            Logout succeeded.
        </p>

        <form class="uk-panel uk-panel-box uk-form" method="post" th:action="@{/web/login}">
            <div class="uk-form-row">
                <input class="uk-width-1-1 uk-form-large" type="text" placeholder="Username" name="username"
                       value="user"/>
            </div>
            <div class="uk-form-row">
                <input class="uk-width-1-1 uk-form-large" type="password" placeholder="Password" name="password"
                       value="password"/>
            </div>
            <div class="uk-form-row">
                <button class="uk-width-1-1 uk-button uk-button-primary uk-button-large">Login</button>
            </div>
        </form>
    </div>
</div>
</body>
</html>

注意 ,这里 form 表单的提交必须使用链接 /web/login

<form class="uk-panel uk-panel-box uk-form" method="post" th:action="@{/web/login}">

如果,将表单的提交链接错误的写成了 /login

<form class="uk-panel uk-panel-box uk-form" method="post" th:action="@{/login}">

如果是这样设置的话,用户登录以后将会报错,报错提示根据相关链接 /login 找不到对应的 Controller;根本原因是, /login 访问链接不能命中 /web/** 安全链,而 login form 既处理表单的部分是通过该安全链中的一个 Filter 既是 LoginFilter 来处理的,而该 Filter 的拦截链接在初始化的时候,其拦截地址,既是 loginUrl 必须匹配 /web/** 的规则,所以,初始化后, loginUrl 的初始值为 /web/login


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

我是一只IT小小鸟

我是一只IT小小鸟

胡江堂、李成、唐雅薇、秦琴、蒋宇东、刘未鹏、居振梁、刘帅、温卫斌、张弦、张凯峰、庄表伟、宋劲杉、程露、黄小明、易晓东、简朝阳、林健、高昂、徐宥、辜新星 / 电子工业出版社 / 2009 / 29.80

一群IT小小鸟—— 来自十几所院校,或男生,或女生;或科班,或半路转行。 分布在不同的公司,或外企,或国企,或民企,老板有土有洋。 有失意,有快意;有泪水,有欢笑。在失望中追求希望,在迷茫中辨别方向。 他们用自己的成长故事,告诉在校的师弟师妹们: 青春太宝贵,千万别浪费;要想不浪费,万事早准备。一起来看看 《我是一只IT小小鸟》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具