天天看點

Spring認證:了解如何使用 Spring Security 保護您的 Web 應用程式

作者:IT膠囊
原标題:Spring認證指南:了解如何使用 Spring Security 保護您的 Web 應用程式。(Spring中國教育管理中心)
Spring認證:了解如何使用 Spring Security 保護您的 Web 應用程式

保護 Web 應用程式

本指南将引導您完成使用受 Spring Security 保護的資源建立簡單 Web 應用程式的過程。

你将建造什麼

您将建構一個 Spring MVC 應用程式,該應用程式使用由固定使用者清單支援的登入表單來保護頁面。

你需要什麼

  • 約15分鐘
  • 最喜歡的文本編輯器或 IDE
  • JDK 1.8或更高版本
  • Gradle 4+或Maven 3.2+
  • 您還可以将代碼直接導入 IDE:
    • 彈簧工具套件 (STS)
    • IntelliJ IDEA

如何完成本指南

像大多數 Spring入門指南一樣,您可以從頭開始并完成每個步驟,也可以繞過您已經熟悉的基本設定步驟。無論哪種方式,您最終都會得到工作代碼。

要從頭開始,請繼續從 Spring Initializr 開始。

要跳過基礎知識,請執行以下操作:

  • 下載下傳并解壓本指南的源代碼庫,或使用Git克隆它:git clone https://github.com/spring-guides/gs-securing-web.git
  • CD光牒進入gs-securing-web/initial
  • 繼續建立不安全的 Web 應用程式。

完成後,您可以對照中的代碼檢查結果gs-securing-web/complete。

從 Spring Initializr 開始

您可以使用這個預先初始化的項目并單擊 Generate 下載下傳 ZIP 檔案。此項目配置為适合本教程中的示例。

手動初始化項目:

  1. 導航到https://start.spring.io。該服務提取應用程式所需的所有依賴項,并為您完成大部分設定。
  2. 選擇 Gradle 或 Maven 以及您要使用的語言。本指南假定您選擇了 Java。
  3. 單擊Dependencies并選擇Spring Web和Thymeleaf。
  4. 單擊生成。
  5. 下載下傳生成的 ZIP 檔案,該檔案是根據您的選擇配置的 Web 應用程式的存檔。

如果您的 IDE 具有 Spring Initializr 內建,您可以從您的 IDE 完成此過程。

你也可以從 Github 上 fork 項目并在你的 IDE 或其他編輯器中打開它。

建立不安全的 Web 應用程式

在将安全性應用到 Web 應用程式之前,您需要一個 Web 應用程式來保護。本部分将引導您建立一個簡單的 Web 應用程式。然後,您将在下一節中使用 Spring Security 對其進行保護。

Web 應用程式包括兩個簡單的視圖:一個首頁和一個“Hello, World”頁面。首頁在以下 Thymeleaf 模闆中定義(來自src/main/resources/templates/home.html):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example</title>
    </head>
    <body>
        <h1>Welcome!</h1>
        
        <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
    </body>
</html>           

這個簡單的視圖包含一個指向/hello頁面的連結,該連結在以下 Thymeleaf 模闆中定義(來自src/main/resources/templates/hello.html):

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

Web 應用程式基于 Spring MVC。是以,您需要配置 Spring MVC 并設定視圖控制器來公開這些模闆。以下清單(來自src/main/java/com/example/securingweb/MvcConfig.java)顯示了在應用程式中配置 Spring MVC 的類:

package com.example.securingweb;

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

@Configuration
public class MvcConfig implements WebMvcConfigurer {

	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/home").setViewName("home");
		registry.addViewController("/").setViewName("home");
		registry.addViewController("/hello").setViewName("hello");
		registry.addViewController("/login").setViewName("login");
	}

}           

該addViewControllers()方法(覆寫 中的同名方法WebMvcConfigurer)添加了四個視圖控制器。兩個視圖控制器引用名稱為home(定義在home.html)的視圖,另一個引用名為hello(定義在hello.html)的視圖。第四個視圖控制器引用另一個名為login. 您将在下一節中建立該視圖。

此時,您可以跳轉到“運作應用程式”并運作應用程式,而無需登入任何東西。

現在您有了一個不安全的 Web 應用程式,您可以為其添加安全性。

設定 Spring Security

假設您要防止未經授權的使用者檢視 的問候語頁面/hello。就像現在一樣,如果通路者點選首頁上的連結,他們會看到沒有阻止他們的障礙。您需要添加一個障礙,強制通路者在看到該頁面之前登入。

您可以通過在應用程式中配置 Spring Security 來做到這一點。如果 Spring Security 在類路徑上,Spring Boot 會自動使用“基本”身份驗證保護所有 HTTP 端點。但是,您可以進一步自定義安全設定。您需要做的第一件事是将 Spring Security 添加到類路徑中。

使用 Gradle,您需要在 in 的dependencies閉包中添加兩行(一行用于應用程式,一行用于測試) build.gradle,如以下清單所示:

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.security:spring-security-test'           

以下清單顯示了完成的build.gradle檔案:

plugins {
	id 'org.springframework.boot' version '2.6.3'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.security:spring-security-test'
	testImplementation('org.springframework.boot:spring-boot-starter-test')
}

test {
	useJUnitPlatform()
}           

使用 Maven,您需要向 中的<dependencies>元素添加兩個額外的條目(一個用于應用程式,一個用于測試) pom.xml,如以下清單所示:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>           

以下清單顯示了完成的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>2.6.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>securing-web-complete</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>securing-web-complete</name>
	<description>Demo project for Spring Boot</description>

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

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-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>           

以下安全配置(來自src/main/java/com/example/securingweb/WebSecurityConfig.java)確定隻有經過身份驗證的使用者才能看到秘密問候:

package com.example.securingweb;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.antMatchers("/", "/home").permitAll()
				.anyRequest().authenticated()
				.and()
			.formLogin()
				.loginPage("/login")
				.permitAll()
				.and()
			.logout()
				.permitAll();
	}

	@Bean
	@Override
	public UserDetailsService userDetailsService() {
		UserDetails user =
			 User.withDefaultPasswordEncoder()
				.username("user")
				.password("password")
				.roles("USER")
				.build();

		return new InMemoryUserDetailsManager(user);
	}
}           

該類WebSecurityConfig被注釋@EnableWebSecurity為啟用 Spring Security 的 Web 安全支援并提供 Spring MVC 內建。它還擴充WebSecurityConfigurerAdapter和覆寫了它的幾個方法來設定 Web 安全配置的一些細節。

該configure(HttpSecurity)方法定義了哪些 URL 路徑應該被保護,哪些不應該。具體來說,/和/home路徑被配置為不需要任何身份驗證。所有其他路徑都必須經過身份驗證。

當使用者成功登入時,他們将被重定向到先前請求的需要身份驗證的頁面。有一個自定義/login頁面(由 指定loginPage()),每個人都可以檢視。

該userDetailsService()方法使用單個使用者設定記憶體中的使用者存儲。該使用者的使用者名是user,密碼是password,角色是USER。

現在您需要建立登入頁面。該視圖已經有一個視圖控制器login,是以您隻需要建立登入視圖本身,如以下清單(來自src/main/resources/templates/login.html)所示:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <div th:if="${param.error}">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}">
            You have been logged out.
        </div>
        <form th:action="@{/login}" method="post">
            <div><label> User Name : <input type="text" name="username"/> </label></div>
            <div><label> Password: <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="Sign In"/></div>
        </form>
    </body>
</html>           

這個 Thymeleaf 模闆提供了一個表單,該表單捕獲使用者名和密碼并将它們釋出到/login. 按照配置,Spring Security 提供了一個過濾器來攔截該請求并對使用者進行身份驗證。如果使用者未能通過身份驗證,頁面将被重定向到/login?error,并且您的頁面會顯示相應的錯誤消息。成功退出後,您的應用程式将發送到/login?logout,并且您的頁面會顯示相應的成功消息。

最後,您需要為通路者提供一種顯示目前使用者名和登出的方式。為此,請更新hello.html以向目前使用者問好并包含一個Sign Out表單,如以下清單(來自src/main/resources/templates/hello.html)所示:

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

我們通過使用 Spring Security 與HttpServletRequest#getRemoteUser(). “退出”表單送出 POST 到/logout. 成功登出後,它将使用者重定向到/login?logout.

運作應用程式

Spring Initializr 為您建立了一個應用程式類。在這種情況下,您不需要修改類。以下清單(來自src/main/java/com/example/securingweb/SecuringWebApplication.java)顯示了應用程式類:

package com.example.securingweb;

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

@SpringBootApplication
public class SecuringWebApplication {

	public static void main(String[] args) throws Throwable {
		SpringApplication.run(SecuringWebApplication.class, args);
	}

}           

建構一個可執行的 JAR

您可以使用 Gradle 或 Maven 從指令行運作應用程式。您還可以建構一個包含所有必要依賴項、類和資源的單個可執行 JAR 檔案并運作它。建構可執行 jar 可以在整個開發生命周期、跨不同環境等中輕松地作為應用程式傳遞、版本化和部署服務。

如果您使用 Gradle,則可以使用./gradlew bootRun. 或者,您可以使用建構 JAR 檔案./gradlew build,然後運作 ​JAR 檔案,如下所示:

java -jar build/libs/gs-securering-web-0.1.0.jar           

如果您使用 Maven,則可以使用./mvnw spring-boot:run. 或者,您可以使用建構 JAR 檔案,./mvnw clean package然後運作該 JAR 檔案,如下所示:

java -jar 目标/gs-securering-web-0.1.0.jar           

此處描述的步驟建立了一個可運作的 JAR。您還可以建構經典的 WAR 檔案。

應用程式啟動後,将浏覽器指向http://localhost:8080. 您應該會看到首頁,如下圖所示:

應用程式的首頁

當您單擊該連結時,它會嘗試将您帶到位于 的問候語頁面/hello。但是,由于該頁面是安全的并且您還沒有登入,它會将您帶到登入頁面,如下圖所示:

登入頁面

如果您使用不安全版本跳到此處,則看不到登入頁面。您應該備份并編寫其餘基于安全性的代碼。

在登入頁面,分别輸入使用者名和密碼字段,以測試使用者身份user登入password。送出登入表單後,您将通過身份驗證,然後進入歡迎頁面,如下圖所示:

安全的問候頁面

如果您單擊登出按鈕,您的身份驗證将被撤銷,您将傳回登入頁面,并顯示一條消息,表明您已登出。

概括

恭喜!您已經開發了一個使用 Spring Security 保護的簡單 Web 應用程式。