[Springboot2.x Security 入门系列] 1.保护web应用的安全

Spring Security是一个灵活和强大的身份验证和访问控制框架,以确保基于Spring的Java Web应用程序的安全,它是轻量级的安全框架,确保基于Spring的应用程序提供身份验证和授权支持。它与Spring MVC能够很好地集成,并配备了流行的安全算法实现捆绑在一起。本系列教程是展示Spring Security 5 的基本和高级的用法,固定URL(依据示例而定),视图和基于Spring boot/Hibernate应用方法的示例等。

特别说明:该教程未做任何关于的Spring MVC或Spring boot开发的基础指导。

一、 目标

你将构建一个Spring MVC应用程序,该应用程序使用一些固定的用户,支持表单登录的形式来保护页面。

二、你需要准备什么

  • 约15分钟
  • 一个你喜欢的文本编辑器或IDE
  • JDK≥1.8
  • Maven 3.0+ or Grandle 2.3+
  • Thymeleaf模板
  • 你也可以将代码直接导入以下IDE:
    Spring Tool Suite (STS)
    IntelliJ IDEA

三、开始

1. 创建目录结构

└── src
    └── main
        └── java
            └── com
                └── spring
                    └── security
                        └── demo

2. 使用Gradle构建

创建gradle文件:build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.7.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

jar {
    baseName = 'gs-securing-web'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    testCompile("junit:junit")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.springframework.security:spring-security-test")
}

3. 使用Maven构建

目录结构不变
文件名:pom.xml


<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.1.RELEASEversion>
        <relativePath/> 
    parent>
    <groupId>com.spring.securitygroupId>
    <artifactId>demoartifactId>
    <version>0.1version>
    <name>demoname>
    <description>Demo project for Spring Boot-Securitydescription>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.securitygroupId>
            <artifactId>spring-security-testartifactId>
            <scope>testscope>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

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

    <repositories>
        <repository>
            <id>spring-releasesid>
            <name>Spring Releasesname>
            <url>https://repo.spring.io/libs-releaseurl>
        repository>
    repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releasesid>
            <name>Spring Releasesname>
            <url>https://repo.spring.io/libs-releaseurl>
        pluginRepository>
    pluginRepositories>

project>

4. 创建不受保护的Web页面

在保护Web应用程序安全之前,先创建两个html页面作为测试使用,此例创建一个非常简单的Web应用程序。 放在下一节中使用Spring Security来保护它。

Web应用程序包括两个简单的视图:
主页-home.html和“Hello World”页面

4.1 “home主页”-home.html

文件路径:src/main/resources/templates/home.html


<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Spring Security 示例title>
head>
<body>
<h1>欢迎!h1>

<p>点击 <a th:href="@{/hello}">这里a> 看看效果.p>
body>
html>

4.2 “hello world页面”-hello.html

文件路径:src/main/resources/templates/hello.html


<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Spring Security 示例-Hello World!title>
head>
<body>
<h1>Hello World!h1>
body>
html>

4.3 Web应用的Spring MVC配置-MvcConfig.java

文件路径:src/main/com/spring/security/config/MvcConfig.java

package com.spring.security.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author: Cavan.Liu
 * @date: 2020-02-16 23:21:35
 * @description:
 */
@Configuration
public class MvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);

        registry.addViewController("/home").setViewName("home");
        registry.addViewController("/").setViewName("home");
        registry.addViewController("/hello").setViewName("hello");
        registry.addViewController("/login").setViewName("login");
    }
}

a. addViewControllers()方法(覆盖WebMvcConfigurationSupport中同名的方法)添加了四个视图控制器。
b. 两个视图控制器引用名称为“home”的视图(在home.html中定义),另一个引用名为“hello”的视图(在hello.html中定义)。
c. 第四个视图控制器引用另一个名为“login”的视图。该视图将在下一部分中创建。

至此,可以执行并运行应用程序,而无需登录操作。在此基础上创建好基本而简单Web应用程序后,可以准备开始添加安全性。

5. 安装Spring Security组件

如果你希望防止用户访问未经授权的“/ hello”。 此时,如果用户点击主页上的链接,会看到问候语,由于未加上任何的防护,请求并被没有被拦截。 因此,咱们需要添加一个访问的前置条件这样用户在看到该页面之前需要先进行登录。

可以通过在应用程序中配置Spring Security来实现。 如果Spring Security在类路径上,则Spring Boot会使用“Basic认证”来自动保护所有HTTP端点。 同时,你可以进一步自定义安全设置,然后我们需要做的第一件事是将Spring Security添加到类路径中。

5.1 添加Spring Security组件

使用Gradle:
文件:build.gradle

dependencies {
    ...
    compile("org.springframework.boot:spring-boot-starter-security")
    ...
}

使用Maven(未添加版本,是因为Springboot会自动匹配最合适的版本):
文件:pom.xml

<dependencies>
    ...
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>
    ...
dependencies>

5.2 添加安全配置

文件路径:src/main/com/spring/security/config/WebSecurityConfig.java

package com.spring.security.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author: Cavan.Liu
 * @date: 2019-11-10 14:06:17
 * @description: 继承WebSecurityConfigurerAdapter,并覆盖一些方法来设置Web安全配置的一些细节
 */
@Configuration
@EnableWebSecurity      // 启用Spring Security的Web安全支持,并提供Spring MVC集成
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * Http security config
     * 定义需要被保护、可直接访问的URL路径
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        super.configure(http);

        http.authorizeRequests()
            // 授权访问 [/]与[/home] 目录
                .antMatchers("/", "/home")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
            // 登录表单
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            // 登出
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置后用户无法正常登录
        //super.configure(auth);

        // 密码编码器
        PasswordEncoder pwdEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

        auth.inMemoryAuthentication()
                .withUser("user")
                .password(pwdEncoder.encode("111111"))
                .roles("USER");
    }
}

@EnableWebSecurity注解的作用
启用Spring Security的Web安全支持,并提供Spring MVC集成。
它还继承了WebSecurityConfigurerAdapter类,并覆盖一些方法来设置Web安全配置的细节。

configure(HttpSecurity)方法的作用
定义了哪些URL路径应该被保护,哪些不应该被保护。具体来说,“/”和“/ home”路径被配置为不需要任何身份验证即可访问,而所有其他路径必须经过身份验证才能访问。

当用户成功登录时,它们将被重定向到先前请求的需要身份认证的页面。有一个由 loginPage()指定的自定义“/登录”页面,每个人都可以查看它。

对于configure(AuthenticationManagerBuilder) 方法,它将单个用户设置在内存中。该用户的用户名为“user”,密码为“111111”,角色为“USER”,方便当前应用的使用,更为简洁,因为此处仅仅是为了验证Security的使用方法,实际生产开发需要配置为数据库的校验。

此时,已经可以正式的创建login.html这个登录页面进行用户名和密码的校验操作。
文件路径:src/main/resources/templates/login.html


<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">

<head>
    <title>Spring Security 示例-登录页面title>
head>

<body>
<div th:if="${param.error}">
    无效的用户名或密码.
div>

<div th:if="${param.logout}">
    你已经登出.
div>

<form th:action="@{/login}" method="post">
    <div>
        <label> 用户名:
            <input type="text" name="username"/>
        label>
    div>
    <div>
        <label> 密码:
            <input type="password" name="password"/>
        label>
    div>
    <div>
        <input type="submit" value="登录"/>
    div>
form>

body>
html>

a. 此处的login页面使用的是Thymeleaf模板,并且只提供一个表单来获取用户名和密码,并将它们提交到“/login”。
b. 根据配置,Spring Security提供了一个拦截该请求并验证用户的过滤器。
c. 如果用户未通过认证,该页面将重定向到“/login?error”,并在页面显示相应的错误消息。 d. 注销成功后,我们的应用程序将发送到“/ login?logout”,我们的页面显示相应的登出成功消息。
e. 最后,我们需要向用户提供一个显示当前用户名和登出的方法。同时,更新hello.html向当前用户打印一句hello,并包含一个“注销”表单。

修改后的hello.html
文件路径:src/main/resources/templates/hello.html


<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Spring Security 示例-Hello World!title>
head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!h1>
<form th:action="@{/logout}" method="post">
    <input type="submit" value="登出"/>
form>
body>
html>

a. hello.html使用Spring Security与HttpServletRequest的getRemoteUser()方法的集成来显示用户名。
b. “登出”表单将POST请求提交到“/logout”成功注销后,便将用户重定向到“/login?logout”。

5.3 添加应用启动方法-Spring boot方式

文件路径:src/main/com/spring/security/security01Application.java

package com.spring.security.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Secury01Application {
    public static void main(String[] args) {
        SpringApplication.run(Secury01Application.class, args);
    }
}

@SpringBootApplication注解的作用(包含以下注解):
a. @Configuration 标记了该类为Spring应用上下文定义Bean的源头。
b. @EnableAutoConfiguration 告诉Spring Boot基于类路径,其他类,多种设置添加Bean的定义。通常你需要为Spring MVC应用添加 @EnableWebMvc注解 , 但springboot如果发现类路径下存在spring-webmvc 的依赖,其会自动添加web的支持。这便将应用标记为了一个web应用,同时激活了核心的配置如 DispatcherServlet。
c. @ComponentScan 告诉Spring去扫描位于com.spring.security 包下的其他组件,配置和服务(components, configurations, and services),同时让它去寻找控制器(controllers)。

至此一个简单的有security保护又类似或者我们熟悉的Java入门级、通过main函数作为入口的web应用就基本构建完成。

6. 启动应用Jar或IDEA中

使用IDEA应用启动,或者使用java -jar方式启动均可。

四、 总结

建议有一定Spring MVC或Spring boot开发经验的同学学习该教程关于Security的集成则收益会大一些。对于Springboot的一些组件学习建议除了可以看我发布的系列教程外,英文有余力的同学应该尽可能看官方提供的说明:spring.io

源码地址

https://github.com/Cavan2477/Springboot2-security01.git

你可能感兴趣的:(Springboot2.x,security,入门系列)