保護web應用的安全

原文:Securing a Web Application

譯者:lexburner

校對:zaixiandemiao

本指南將引導你使用Spring Security來保護Web應用的安全。

你將要構建什麼

你將構建一個Spring MVC應用程序,該應用程序使用一些固定的用戶,支持表單登錄的形式來保護頁面。

你需要什麼

  • 約15分鐘
  • 一個你喜歡的文本編輯器或IDE
  • JDK≥1.8
  • Gradle 2.3+ or Maven 3.0+
  • 你也可以將代碼直接導入你的IDE:
    • Spring Tool Suite (STS)
    • IntelliJ IDEA

如何完成這篇指南

像大多數的Spring指南 Getting Started guides,你可以從頭開始,完成每一步,也可以跳過已經熟悉的基本設置。 無論哪種方式,你都會得到起作用的代碼。

如果從基礎開始, 移步 使用Gradle構建.

如果你想跳過基礎部分, 執行以下操作:

  • 下載 並解壓本倉庫的源碼, 或者使用 Git: git clone https://github.com/spring-guides/gs-securing-web.git
  • 進入 gs-securing-web/initial
  • 前往 安裝 Spring Security.

當你完成後, 你可以和此處的代碼進行對比 gs-securing-web/complete.

<h2 id="scratch">使用Gradle構建</h2>

首先你得安裝基礎的構建腳本. 可以使用任意你喜歡的構建系統去構建Spring應用, 而使用 Gradle 和 Maven構建需要的代碼在本文提供: Gradle 和 Maven . 如果你對兩者都不熟悉,可以先參考Building Java Projects with Gradle 或者 Building Java Projects with Maven.

創建目錄結構

在你選擇的項目目錄中,創建以下子目錄結構;例如, 在Linux/Unix系統中使用如下命令: mkdir -p src/main/java/hello

└── srcn └── mainn └── javan └── hellon

創建一個Gradle文件

如下是一個 Gradle初始化文件:

build.gradle

buildscript {n repositories {n mavenCentral()n }n dependencies {n classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.7.RELEASE")n }n}nnapply plugin: javanapply plugin: eclipsenapply plugin: ideanapply plugin: org.springframework.bootnnjar {n baseName = gs-securing-webn version = 0.1.0n}nnrepositories {n mavenCentral()n}nnsourceCompatibility = 1.8ntargetCompatibility = 1.8nndependencies {n compile("org.springframework.boot:spring-boot-starter-thymeleaf")n testCompile("junit:junit")n testCompile("org.springframework.boot:spring-boot-starter-test")n testCompile("org.springframework.security:spring-security-test")nn}n

Spring Boot gradle 插件 提供了很多便捷的特性:

  • 它收集類路徑上的所有jar包,並構建一個可運行的jar包,這樣可以更方便地執行和發布服務。
  • 它尋找public static void main() 方法並標記為一個可執行的類.
  • 它提供了一個內置的依賴解析器,將應用與Spring Boot依賴的版本號進行匹配。你可以修改成任意的版本,但它將默認為Boot所選擇的一組版本。

使用Maven構建

首先,你需要設置一個基本的構建腳本。當使用Spring構建應用程序時,你可以使用任何你喜歡的構建系統,而使用 Maven 構建的代碼如下所示。如果你不熟悉Maven,請參考使用Maven構建Java項目。

創建目錄結構

在你選擇的項目目錄中,創建以下子目錄結構;例如, 在Linux/Unix系統中使用如下命令: mkdir -p src/main/java/hello

└── srcn └── mainn └── javan └── hellon

pom.xml

<?xml version="1.0" encoding="UTF-8"?>n<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"n xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">n <modelVersion>4.0.0</modelVersion>nn <groupId>org.springframework</groupId>n <artifactId>gs-securing-web</artifactId>n <version>0.1.0</version>nn <parent>n <groupId>org.springframework.boot</groupId>n <artifactId>spring-boot-starter-parent</artifactId>n <version>1.5.7.RELEASE</version>n </parent>nn <dependencies>n <dependency>n <groupId>org.springframework.boot</groupId>n <artifactId>spring-boot-starter-thymeleaf</artifactId>n </dependency>n <dependency>n <groupId>org.springframework.boot</groupId>n <artifactId>spring-boot-starter-test</artifactId>n <scope>test</scope>n </dependency>n <dependency>n <groupId>org.springframework.security</groupId>n <artifactId>spring-security-test</artifactId>n <scope>test</scope>n </dependency>n </dependencies>nn <properties>n <java.version>1.8</java.version>n </properties>nn <build>n <plugins>n <plugin>n <groupId>org.springframework.boot</groupId>n <artifactId>spring-boot-maven-plugin</artifactId>n </plugin>n </plugins>n </build>nn <repositories>n <repository>n <id>spring-releases</id>n <name>Spring Releases</name>n <url>https://repo.spring.io/libs-release</url>n </repository>n </repositories>n <pluginRepositories>n <pluginRepository>n <id>spring-releases</id>n <name>Spring Releases</name>n <url>https://repo.spring.io/libs-release</url>n </pluginRepository>n </pluginRepositories>n</project>n

Spring Boot Maven 插件 提供了很多便捷的特性:

  • 它收集類路徑上的所有jar包,並構建一個可運行的jar包,這樣可以更方便地執行和發布服務。
  • 它尋找public static void main() 方法並標記為一個可執行的類.
  • 它提供了一個內置的依賴解析器,將應用與Spring Boot依賴的版本號進行匹配。你可以修改成任意的版本,但它將默認為Boot所選擇的一組版本。

使用你的IDE構建

  • 閱讀如何導入這篇指南進入你的IDE Spring Tool Suite.
  • 閱讀如何使用 IntelliJ IDEA 來構建.

創建一個不受安全保護的web應用

在保護Web應用程序安全之前,您需要安裝Web應用程序。 本節將引導你創建一個非常簡單的Web應用程序。 然後在下一節中使用Spring Security來保護它。

Web應用程序包括兩個簡單的視圖:主頁和「Hello World」頁面。 主頁定義在如下的Thymeleaf模板中:

src/main/resources/templates/home.html

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

我們可以看到, 在這個簡單的視圖中包含了一個鏈接: 「/hello」. 鏈接到了如下的頁面,Thymeleaf模板如下:

src/main/resources/templates/hello.html

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

Web應用程序基於Spring MVC。 因此,你需要配置Spring MVC並設置視圖控制器來暴露這些模板。 如下是一個典型的Spring MVC配置類。

src/main/java/hello/MvcConfig.java

package hello;nnimport org.springframework.context.annotation.Configuration;nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;nn@Configurationnpublic class MvcConfig extends WebMvcConfigurerAdapter {nn @Overriden public void addViewControllers(ViewControllerRegistry registry) {n registry.addViewController("/home").setViewName("home");n registry.addViewController("/").setViewName("home");n registry.addViewController("/hello").setViewName("hello");n registry.addViewController("/login").setViewName("login");n }nn}n

addViewControllers()方法(覆蓋WebMvcConfigurerAdapter中同名的方法)添加了四個視圖控制器。 兩個視圖控制器引用名稱為「home」的視圖(在home.html中定義),另一個引用名為「hello」的視圖(在hello.html中定義)。 第四個視圖控制器引用另一個名為「login」的視圖。 您將在下一部分中創建該視圖。

此時,您可以跳過來使應用程序可執行並運行應用程序,而無需登錄任何內容。

創建基本的簡單Web應用程序後,可以添加安全性。

安裝 Spring Security

假設你希望防止未經授權的用戶訪問「/ hello」。 此時,如果用戶點擊主頁上的鏈接,他們會看到問候語,請求被沒有被攔截。 你需要添加一個障礙,使得用戶在看到該頁面之前登錄。

您可以通過在應用程序中配置Spring Security來實現。 如果Spring Security在類路徑上,則Spring Boot會使用「Basic認證」來自動保護所有HTTP端點。 同時,你可以進一步自定義安全設置。 你需要做的第一件事是將Spring Security添加到類路徑中。

使用Gradle:

build.gradle

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

使用maven,需要添加到 <dependencies>節點中 :

pom.xml

<dependencies>n ...n <dependency>n <groupId>org.springframework.boot</groupId>n <artifactId>spring-boot-starter-security</artifactId>n </dependency>n ...n</dependencies>n

如下是安全配置,使得只有認證過的用戶才可以訪問到問候頁面:

src/main/java/hello/WebSecurityConfig.java

package hello;nnimport org.springframework.beans.factory.annotation.Autowired;nimport org.springframework.context.annotation.Configuration;nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;nn@Configurationn@EnableWebSecuritynpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {n @Overriden protected void configure(HttpSecurity http) throws Exception {n httpn .authorizeRequests()n .antMatchers("/", "/home").permitAll()n .anyRequest().authenticated()n .and()n .formLogin()n .loginPage("/login")n .permitAll()n .and()n .logout()n .permitAll();n }nn @Autowiredn public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {n authn .inMemoryAuthentication()n .withUser("user").password("password").roles("USER");n }n}n

WebSecurityConfig類使用了@EnableWebSecurity註解 ,以啟用Spring Security的Web安全支持,並提供Spring MVC集成。它還擴展了WebSecurityConfigurerAdapter,並覆蓋了一些方法來設置Web安全配置的一些細節。

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

當用戶成功登錄時,它們將被重定向到先前請求的需要身份認證的頁面。有一個由 loginPage()指定的自定義「/登錄」頁面,每個人都可以查看它。

對於configureGlobal(AuthenticationManagerBuilder) 方法,它將單個用戶設置在內存中。該用戶的用戶名為「user」,密碼為「password」,角色為「USER」。

現在我們需要創建登錄頁面。前面我們已經配置了「login」的視圖控制器,因此現在只需要創建登錄頁面即可:

src/main/resources/templates/login.html

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

你可以看到,這個Thymeleaf模板只是提供一個表單來獲取用戶名和密碼,並將它們提交到「/ login」。 根據配置,Spring Security提供了一個攔截該請求並驗證用戶的過濾器。 如果用戶未通過認證,該頁面將重定向到「/ login?error」,並在頁面顯示相應的錯誤消息。 註銷成功後,我們的應用程序將發送到「/ login?logout」,我們的頁面顯示相應的登出成功消息。

最後,我們需要向用戶提供一個顯示當前用戶名和登出的方法。 更新hello.html 向當前用戶列印一句hello,並包含一個「註銷」表單,如下所示:

src/main/resources/templates/hello.html

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

我們使用Spring Security與HttpServletRequest#getRemoteUser()的集成來顯示用戶名。 「登出」表單將POST請求提交到「/ logout」。 成功註銷後,會將用戶重定向到「/ login?logout」。

讓應用跑起來

雖然可以將此服務打包成傳統的Web應用程序或WAR 包以部署到外部的應用伺服器,但下面將演示一種更簡單的方法,創建一個獨立的應用程序。 所有內容都將包裝在一個可執行的JAR文件中,並使用Java的main()方法驅動。 這樣,你就可以使用Spring提供的內嵌Tomcat servlet容器,來運行HTTP服務,而不是部署到外部實例。

src/main/java/hello/Application.java

package hello;nnimport org.springframework.boot.SpringApplication;nimport org.springframework.boot.autoconfigure.SpringBootApplication;nn@SpringBootApplicationnpublic class Application {nn public static void main(String[] args) throws Throwable {n SpringApplication.run(Application.class, args);n }nn}n

@SpringBootApplication 是一個便捷的註解,它包含了如下的作用:

  • @Configuration 標記了該類為Spring應用上下文定義Bean的源頭.
  • @EnableAutoConfiguration 告訴Spring Boot基於類路徑,其他類,多種設置添加Bean的定義.
  • 通常你需要為Spring MVC應用添加 @EnableWebMvc註解 , 但springboot如果發現類路徑下存在spring-webmvc 的依賴,其會自動添加web的支持. 這便將應用標記為了一個web應用 並且激活了核心的配置如 DispatcherServlet.
  • @ComponentScan 告訴Spring去掃描位於hello 包下的其他組件,配置和服務( components, configurations, and services), 同時讓它去尋找控制器(controllers).

main() 方法使用Spring Boot的 SpringApplication.run() 方法去運行應用. 發現沒有,我們沒有寫任何一行XML?也不存在 web.xml 文件. 這個web應用100%都是 Java 並且你不必配置任何基礎設施。

構建可執行的JAR包

你可以使用Gradle或Maven,從命令行運行應用程序。 或者,你可以構建一個包含所有依賴,類和資源的單個可執行JAR文件,並運行該文件。 這使得在整個開發生命周期中,可以很方便地跨不同的環境和版本,和部署服務成為一個應用程序。

如果你使用gradle, 你可以使用 ./gradlew bootRun命令運行. 或者你可以使用 ./gradlew build構建一個JAR . 然後你可以運行這個 JAR文件:

java -jar build/libs/gs-securing-web-0.1.0.jarn

如果你使用maven, 你可以使用 ./mvnw spring-boot:run命令運行. 或者你可以使用 ./mvnw clean package構建一個JAR. 然後你可以運行這個 JAR文件:

java -jar target/gs-securing-web-0.1.0.jarn

上述的過程將會創建一個可運行的JAR包. 你也可以在這兒獲知如何 構建一個傳統的WAR包.

... app starts up ...n

應用啟動後, 在瀏覽器中訪問 http://localhost:8080. 你可以訪問到首頁:

當你點擊鏈接,他將會讓你試圖去訪問 /hello. 但因為該頁面是受保護的,所以你需要登錄, 於是來到了登錄頁面。

如果您使用未收保護的代碼版本訪問此處,那麼你將看不到此登錄頁面。 隨時備份和編寫其餘的受安全保護的代碼。

在登錄頁面,分別輸入用戶名和密碼欄位的」user」和」password」作為測試用戶登錄。 提交登錄表單後,你將進行身份認證,然後轉到問候頁面:

如果點擊「退出」按鈕,您的身份認證將被註銷,並返回到登錄頁面,並顯示一條消息,提示你已註銷。

總結

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

發現

以下指南也可能有幫助:

  • 使用SpringBoot構建應用程序
  • 使用Spring MVC提供Web內容
  • Spring Security 架構 (Reference guide)
  • Spring Security and Angular JS (Tutorial)

作者:SpringForAll

鏈接:保護web應用的安全 | Spring For All

聲明:本文轉載於SpringForAll,版權歸作者所有,有什麼問題,請聯繫我們,謝謝!

推薦閱讀:

家居用品中有哪些安全隱患,需要大家注意,或是設計師進一步改善?
如何進入安全公司實習或工作2--你該怎麼做?
不用水的免洗洗手液,到底有沒有那麼神奇?
2016阿里安全峰會重點資料下載
修正液苯超標400倍 你還敢讓孩子用么?

TAG:Spring | 安全 | Web开发 |