Spring Security 6 学习-1

发布时间:2024年01月24日

什么是 Spring Security

Spring Security文档
Spring Security中文文档

Spring Security 是 Spring 家族中的安全型开发框架,主要解决三大方面问题:认证(你是谁)、授权(你能干什么)、常见攻击保护(CSRF、HTTP安全响应头设置、Http防火墙)。它常用于 Spring Boot 及 Spring Cloud 框架中。总体架构核心非常简单,在国内大部分使用其Servlet应用的功能,其就在Filter一点上扩展,但学习来优点复杂,因为安全考虑的方面太多、应用场景也多,所以集成的功能也挺多,不过它提供了一个综合的解决方案,后面的 Spring Authorization Server 也是在 Security 基础上构建的,所以也是必学内容。

示例

下面通过一个例子来简单测试下:
首先在 idea 中新建 Spring Initializr 应用,环境如下:

JDK 17
Spring Boot 3.2.2
Maven 3.8.8

加入 Spring Security 包,完整的 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.alex</groupId>
    <artifactId>security-01-hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>security-01-hello</name>
    <description>security-01-hello</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>

        <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-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

新建一个 HelloController:

package com.alex.security01hello;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("hello")
    private String hello() {
        return "Hello, Spring Security!";
    }
}

运行程序

然后运行启动程序,这里是:Security01HelloApplication main
此时通过浏览器访问: http://127.0.0.1:8080/hello,页面会被重定向到 http://127.0.0.1:8080/login,此时查看 idea 的 Console ,会有生成的密码:
在这里插入图片描述
在 login 页面,输入 user 及上面的密码,就可以访问到 hello api 输出的内容。
在这里插入图片描述

背后原理

Spring Security 还挺复杂,当在运行上面程序的时候,其在背后执行了很多个步骤,可以参考官方文档:
在这里插入图片描述
这里根据官方文档,可以固定一个 用户名、密码及角色,避免再查看控制台的复杂密码:


@EnableWebSecurity
@Configuration
public class DefaultSecurityConfig {

    @Bean
    @ConditionalOnMissingBean(UserDetailsService.class)
    InMemoryUserDetailsManager inMemoryUserDetailsManager() {
        UserDetails user = org.springframework.security.core.userdetails.User.withDefaultPasswordEncoder()
                .username("user")
                .password("password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    @ConditionalOnMissingBean(AuthenticationEventPublisher.class)
    public DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher() {
        return new DefaultAuthenticationEventPublisher();
    }
}

再次重启程序,如果被重定向到登录页,直接输入 user+password 即可登录。
下面通过配置日志,查看 Spring Security 在请求时做了啥,首先在 resources/application.properties 配置 Spring Security 日志:
application.properties:

logging.level.org.springframework.security=TRACE

然后配置 logback 日志,在 resources下添加 logback.xml:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="WARN">
        <appender-ref ref="STDOUT" />
    </root>

</configuration>

重启程序,在浏览器中输入:127.0.0.1:8080/hello,观察控制台会输出相关日志:
在这里插入图片描述
通过上面可以看出,在访问的时候,一个 Filter 链中包含了16个 Filter, 最终因为在 AuthorizationFilter 的 doFilter 方法中抛出 AccessDeniedException 异常,并且重定向到 login 页面:

在这里插入图片描述
我们访问的 login 页面是在 DefaultLoginPageGeneratingFilter 中生成的:
在这里插入图片描述

参考:自定义登录页

文章来源:https://blog.csdn.net/xingkongtianyuzhao/article/details/135791959
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。