转载

[译]Spring入门 - Web应用程序安全

原网页 https://spring.io/guides/gs/securing-web/

本指南将引导您完成创建一个资源由Spring Security的保护的一个简单的Web应用程序的过程。

你将构建

你将构建一个通过固定的用户列表作为后端的登录表单来保护页面安全的Spring MVC应用程序

你将需要

  • 大约15分钟

  • 一个喜欢的文本编辑器或IDE

  • JDK 1.8 或更高版本

  • Gradle 2.3+ 或 Maven 3.0+

  • 你同样可以将本指南的代码直接导入Spring Tool Suite (STS)并从这里开始你的工作

如何完成这个指南

如同大多数的 Spring入门指南 ,你可以从头开始并完成每一个步骤,或者可以跳过这个你已经熟悉的基本配置过程。无论哪种方式,您最终会获得可运行的代码。

要从头开始,请看“使用gradle构建”部分。

要跳过最基本的部分,按下面的步骤操作:

  • 下载 然后解压本项目的代码,或者使用 Git 克隆一个代码仓库:

    git clone https://github.com/spring-guides/gs-securing-web.git

  • cd 到 gs-securing-web/initial 目录

  • 直接跳到“部署Spring Security”

使用gradle构建

首先,你要创建一个基本的构建脚本。你可以使用任何你喜欢的构建系统来构建Spring应用程序,但是你所需要的Gralde和Maven构建代码已经包含在这里了。如果你对两者都不熟悉,可以参考“ 使用Gradle构建Java项目 ”或“ 使用Maven构建Java项目 ”。

创建目录结构

你需要在你选的一个用作项目目录的文件夹中,创建下面的子目录结构;例如你可以在*nix系统中使用 mkdir -p src/main/java/hello 这样的命令来完成。

└── src     └── main         └── java             └── hello 

创建Gradle的build文件

下面是initial目录下的Gradle的build文件(译注:实际这个initial指的是项目的根目录,它包含了上面所创建的src目录,以及gradle.build文件,这样执行 gradle build 命令时,gradle才能正确地找到要构建的代码)。

文件名: build.gradle

buildscript {     repositories {         mavenCentral()     }     dependencies {         classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.5.RELEASE")     } }  apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'spring-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") }  task wrapper(type: Wrapper) {     gradleVersion = '2.3' } 

使用maven构建

略,请参考 原文

使用IDE构建

略,请参考 原文

创建一个不安全的Web应用

在你可以尝试将安全性应用于Web应用之前,你需要一个用于“保护”的Web应用程序。本节中的步骤指导您完成创建一个非常简单的Web应用程序。然后你将在下一节使用Spring Security将其保护起来。

这个web应用程序包括两个简单的视图,一个是“主页”,一个是“Hello World”页。“主页”的视图由下面这个themeleaf模板来定义:

文件名: src/main/resources/templates/home.html

<!DOCTYPE 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 Example</title>     </head>     <body>         <h1>Welcome!</h1>          <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>     </body> </html> 

如你所见,这个简单的视图包括一个指向“/hello”页面的链接,它由下面这个themeleaf模板来定义:

src/main/resources/templates/hello.html

<!DOCTYPE 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>Hello World!</title>     </head>     <body>         <h1>Hello world!</h1>     </body> </html> 

这个Web应用基于Spring MVC,因此你需要配置Spring MVC,然后设置view controller来暴露这些模板。下面就是一个配置好Spring MVC的Class。

文件名: src/main/java/hello/MvcConfig.java

package hello;  import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  @Configuration public class MvcConfig extends WebMvcConfigurerAdapter {      @Override     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() 方法(覆盖了 WebMvcConfigurerAdapter 的同名方法)添加了四个view controller。其中两个view controller指向了“home”视图(在 home.html 中定义),另一个指向了“hello”视图(在 hello.html 中定义)。第四个view controller指向另一个视图“login”,你将会在下个章节创建这个视图。

此刻,你可以直接跳到“让Web应用可执行”的部分,在不需要任何登陆工作的情况下运行Web应用。

一旦最基本的Web应用创建好了,你可以给他加上安全防护。

部署Spring Security

假设现在你希望防止未授权的用户在输入“/hello”这个网址后看到欢迎页的内容。当前状态下,如果用户点击“home”页上的链接,他们可以没有任何阻碍地看到欢迎页。现在你需要在用户看到这个页面前添加一个强制用户登录的阻碍。

你可以通过配置Spring Security来完成上面所说的事。如果Spring Security在classpath中,SpringBoot会自动使用“基本”HTTP认证来保护所有HTTP端点,你也可以进一步的定制安全设置。首先要做的事情就是把Spring Security加入到classpath中。

如果使用Gradle,它将会是 dependencies 部分中的一行:

文件名: build.gradle

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

如果使用Maven,他将会是 <dependencies> 标签中的一个子标签:

文件名: pom.xml

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

下面是确保只有认证过的用户才能看到“秘密的”欢迎页的安全配置:

文件名: src/main/java/hello/WebSecurityConfig.java

package hello;  import org.springframework.beans.factory.annotation.Autowired; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;  @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();     }      @Autowired     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {         auth             .inMemoryAuthentication()                 .withUser("user").password("password").roles("USER");     } } 

这个 WebSecurityConfig 类被 @EnableWebMvcSecurity 标注,来启用Spring Security的web安全支持、以及提供与Spring MVC的融合。这个类还继承了 WebSecurityConfigurerAdapter 并重写了一些方法来指定一些特定的Web安全设置。

configure(HttpSecurity) 方法规定了哪个URL应该被保护,哪个不应该。具体而言,“/”和“/home”的路径被配置为不需要任何认证。所有其他URL必须进行身份验证。

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

对于 configureGlobal(AuthenticationManagerBuilder) 方法,它设置了一个单一用户在内存中的用户数据库。该用户被赋予“user”的用户名,“password”的密码,以及“USER”作为角色。

现在,我们需要创建登录页面。目前已经为“login”视图赋予了视图控制器,所以你只需要创建login视图本身:

文件名: src/main/resources/templates/login.html

<!DOCTYPE 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 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模板只是给出了一个采集用户名和密码,并将它们作为请求post到“/login”的表单。正如刚刚配置的,Spring Security提供一个过滤器,截取该请求,并验证用户身份。如果用户身份验证失败,页面被重定向到“/login?error”,我们的页面将显示相应的错误信息。一旦成功登出了,我们的应用程序重定向到到“/login?logout”并显示相应的登陆成功的消息。

最后,我们需要给用户提供一种方式来显示当前用户名和“Sign Out”按钮。更新 hello.html 来问好当前用户,并包含一个“Sign Out”的按钮,如下所示:

文件名: src/main/resources/templates/hello.html

<!DOCTYPE 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>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() 来显示用户名。该“Sign Out”按钮提交一个POST请求给“/logout”。一旦成功退出,将用户重定向到“/login?logout”。

让Web应用可执行

虽然可以打包这项服务作为一个传统的web应用程序归档或 WAR 文件部署到外部应用服务器,下面展示了更简单的方法来创建一个独立的应用程序。你将打包一切到一个单一的,可执行的JAR文件中,用一个良好旧式Java main() 方法来调用。在此过程中,你会用到Spring所支持的嵌入式 Tomcat servlet容器作为HTTP运行实例,而不是部署一个外部实例。

文件名: src/main/java/hello/Application.java

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

@SpringBootApplication 是个方便的注解,自动添加了所有以下内容:

  • @Configuration 标记这个类作为bean以定义应用程序上下文的来源。

  • @EnableAutoConfiguration 告诉SpringBoot开始添加基于classpath设置,其他Beans,以及各种属性设置的Beans。

  • 通常情况下你会给Spring MVC应用加上 @EnableWebMvc 注解,但当Spring Boot看到classpath中有 spring-webmvc 时,会自动添加这个注解。这标记该应用程序是一个Web应用程序,并激活一些关键行为,比如创建一个 DispatcherServlet

  • @ComponentScan 告诉Spring去 hello 包中寻找其他组件,配置,服务。

main() 方法使用Spring Boot的 SpringApplication.run() 方法来启动应用程序。你有没有注意到,这里没有一行XML,同样也没有 web.xml 文件。这个Web应用程序是100%纯Java写的,你不必处理配置任何管道或基础设施(译注:plumbing or infrastructure,我这里直译了)。

构建一个可执行的JAR包

如果你正在使用gradle,你可以使用 ./gradlew bootRun 命令来运行应用程序。

你可以构建一个包含所有必要的依赖,类和资源的一个可执行的JAR文件。这样使传输,版本管理和部署服务在整个开发生命周期在不同的环境,等等,变得更容易

./gradlew build 

然后你可以这样运行JAR包:

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

如果你正在使用Maven,你可以通过 mvn spring-boot:run 来运行应用,或者你也可以通过 mvn clean package 来构建JAR包,然后输入下面的命令来运行:

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

注意:上述过程将创建一个可运行的JAR。你也可以选择构建一个经典的WAR包来代替。

一旦应用程序启动,用浏览器访问 http://localhost:8080 。你应该看到主页:

[译]Spring入门 - Web应用程序安全

当你点击这个链接,它会尝试把你带到 /hello 所指向的欢迎页,但因为这个页面是受保护的,而且目前为止你没有登录,它会带你到登陆页

[译]Spring入门 - Web应用程序安全

注意:如果你是直接从“不安全”的版本跳到这的,那么你将不会看到登陆页,请放松地回到上面写完其余的基于安全的代码

在登录页面,分别输入“user”和“password”作为用户名和密码,即可作为测试用户登录。一旦你提交登录表单,你会被进行身份验证,然后带你到欢迎页:

[译]Spring入门 - Web应用程序安全

如果你点击“Sign Out”按钮,你的身份验证被撤销,你将会返回到登录页并显示一个消息提示你已经登出。

小结

恭喜你,你已经开发了一个简单的、使用Spring Security来保护的Web应用。

想写一个新的指南,或向已有的指南贡献自己的能力?请看我们的 贡献指南

原文  https://segmentfault.com/a/1190000005685793
正文到此结束
Loading...