Spring Security和Angular教程(一)
安全的单页应用程序
在本教程中,我们展示了Spring Security,Spring Boot和Angular的一些很好的功能,它们协同工作以提供愉快和安全的用户体验。Spring和Angular的初学者应该可以访问它,但是也有很多细节可供专家使用。这实际上是Spring Security和Angular系列部分中的第一部分,其中每个部分都依次公开了新功能。我们将在第二部分和后续部分中改进应用程序,但此后的主要更改是体系结构而非功能性。
Spring和单页应用程序
HTML5,丰富的基于浏览器的功能和“单页面应用程序”是现代开发人员非常有价值的工具,但任何有意义的交互都将涉及后端服务器,以及静态内容(HTML,CSS和JavaScript),我们将采用需要一个后端服务器。后端服务器可以扮演任何或所有角色:提供静态内容,有时(但现在不常见)渲染动态HTML,验证用户,保护对受保护资源的访问,以及(最后但并非最不重要)与JavaScript交互在浏览器中通过HTTP和JSON(有时称为REST API)。
Spring一直是构建后端功能的流行技术(特别是在企业中),随着Spring Boot的出现,事情变得前所未有的简单。让我们看看如何使用Spring Boot,Angular和Twitter Bootstrap从零开始构建新的单页面应用程序。没有特别的理由选择那个特定的堆栈,但它很受欢迎,特别是在企业Java商店的核心Spring选区,所以这是一个有价值的起点。
创建一个新项目
我们将逐步详细地创建这个应用程序,这样任何不完全使用Spring和Angular的人都可以关注正在发生的事情。如果您希望切换到追逐,您可以跳到应用程序正在运行的末尾,并查看它们如何组合在一起。创建新项目有多种选择:
我们要构建的完整项目的源代码在Github中,所以你可以克隆项目并直接从那里开始工作。然后跳到下一部分。
使用卷曲
创建新项目以开始的最简单方法是通过Spring Boot Initializr。例如在类似UN * X的系统上使用curl:
$ mkdir ui && cd ui
$ curl https://start.spring.io/starter.tgz -d style=web \
-d style=security -d name=ui | tar -xzvf -
然后,您可以将该项目(默认情况下是普通的Maven Java项目)导入您喜欢的IDE,或者只使用命令行中的文件和“mvn”。然后跳到下一部分。
使用Spring Boot CLI
您可以使用Spring Boot CLI创建相同的项目,如下所示:
$ spring init --dependencies web,security ui/ && cd ui
然后跳到下一部分。
使用Initializr网站
如果您愿意,也可以直接从Spring Boot Initializr获取与.zip文件相同的代码。只需在浏览器中打开它并选择依赖项“Web”和“安全性”,然后单击“生成项目”。.zip文件在根目录中包含标准Maven或Gradle项目,因此您可能需要在解压缩之前创建一个空目录。然后跳到下一部分。
使用Spring Tool Suite
在Spring Tool Suite(一组Eclipse插件)中,您还可以使用向导创建和导入项目File->New->Spring Starter Project
。然后跳到下一部分。IntelliJ IDEA和NetBeans具有类似的功能。
添加角度应用程序
如今,Angular(或任何现代前端框架)中的单页面应用程序的核心将是Node.js构建。Angular有一些工具可以快速设置它,所以让我们使用它们,并保留使用Maven构建的选项,就像任何其他Spring Boot应用程序一样。有关如何设置Angular应用程序的详细信息将在其他地方介绍,或者您可以从github查看本教程的代码。
运行应用程序
一旦Angular应用程序启动,您的应用程序将可以在浏览器中加载(即使它还没有做太多)。在命令行上,您可以执行此操作
$ mvn spring-boot:run
并转到http:// localhost:8080的浏览器。当您加载主页时,您应该获得一个浏览器对话框,询问用户名和密码(用户名是“user”,密码在启动时在控制台日志中打印)。实际上还没有任何内容(或者可能是来自ng
CLI 的默认“英雄”教程内容),所以你应该基本上得到一个空白页面。
如果您不喜欢在控制台日志中输入密码,只需将其添加到“application.properties”(在“src / main / resources”中):( security.user.password=password 并选择您自己的密码)。我们使用“application.yml”在示例代码中完成了此操作。 |
在IDE中,只需main()
在应用程序类中运行该方法(只有一个类,UiApplication
如果使用上面的“curl”命令则调用它)。
要打包并作为独立的JAR运行,您可以这样做:
$ mvn package
$ java -jar target/*.jar
自定义角度应用程序
让我们自定义“app-root”组件(在“src / app / app.component.ts”中)。
最小的Angular应用程序如下所示:
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Demo';
greeting = {'id': 'XXX', 'content': 'Hello World'};
}
此TypeScript中的大多数代码都是锅炉板。有趣的东西都将出现在AppComponent
我们定义“selector”(HTML元素的名称)的地方,以及通过@Component
注释呈现的HTML片段。我们还需要编辑HTML模板(“app.component.html”):
app.component.html
<div style="text-align:center"class="container">
<h1>
Welcome {{title}}!
</h1>
<div class="container">
<p>Id: <span>{{greeting.id}}</span></p>
<p>Message: <span>{{greeting.content}}!</span></p>
</div>
</div>
如果您在“src / app”下添加了这些文件并重建了应用程序,它现在应该是安全且实用的,它会说“Hello World!”。在greeting
由角在HTML中使用车把呈现占位符,{{greeting.id}}
和{{greeting.content}}
。
添加动态内容
到目前为止,我们有一个带有硬编码问候语的应用程序。这对于了解事物是如何组合在一起很有用,但实际上我们希望内容来自后端服务器,所以让我们创建一个HTTP端点,我们可以使用它来获取问候语。在您的应用程序类中(在“src / main / java / demo”中),添加@RestController
注释并定义一个新的@RequestMapping
:
UiApplication.java
@SpringBootApplication
@RestController
public class UiApplication {
@RequestMapping("/resource")
public Map<String,Object> home() {
Map<String,Object> model = new HashMap<String,Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
}
根据您创建新项目的方式,可能不会调用它UiApplication 。 |
运行该应用程序并尝试卷曲“/ resource”端点,您会发现默认情况下它是安全的:
$ curl localhost:8080/resource
{"timestamp":1420442772928,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/resource"}
从Angular加载动态资源
所以让我们在浏览器中抓取该消息。修改AppComponent
以使用XHR加载受保护资源:
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Demo';
greeting = {};
constructor(private http: HttpClient) {
http.get('resource').subscribe(data => this.greeting = data);
}
}
我们注入了一个由Angular通过模块提供的http
服务,http
并用它来获取我们的资源。Angular将响应传递给我们,我们提取JSON并将其分配给问候语。
为了将http
服务依赖注入到我们的自定义组件中,我们需要在AppModule
包含组件的组件中声明它(imports
与初始草稿相比,它只是一行):
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
再次运行应用程序(或只是在浏览器中重新加载主页),您将看到带有唯一ID的动态消息。因此,即使资源受到保护而您无法直接卷曲,浏览器也能够访问内容。我们有一个安全的单页应用程序,不到一百行代码!
您可能需要强制浏览器在更改后重新加载静态资源。在Chrome(以及带有插件的Firefox)中,您可以使用“开发人员工具”(F12),这可能就足够了。或者您可能必须使用CTRL + F5。 |
它是如何工作的?
如果您使用某些开发人员工具,则可以在浏览器中看到浏览器和后端之间的交互(通常F12打开它,默认情况下在Chrome中运行,可能需要Firefox中的插件)。这是一个总结:
动词 | 路径 | 状态 | 响应 |
---|---|---|---|
得到 | / | 401 | 浏览器提示进行身份验证 |
得到 | / | 200 | 的index.html |
得到 | /*.js | 200 | 角度来自第三资产的负荷 |
得到 | /main.bundle.js | 200 | 应用逻辑 |
得到 | /资源 | 200 | JSON问候语 |
您可能看不到401,因为浏览器将主页加载视为单个交互,您可能会看到2个“/ resource”请求,因为存在CORS协商。
仔细查看请求,您将看到所有这些请求都有一个“授权”标题,如下所示:
Authorization: Basic dXNlcjpwYXNzd29yZA==
浏览器正在为每个请求发送用户名和密码(因此请记住在生产中使用HTTPS)。没有什么“Angular”,所以它适用于您的JavaScript框架或非框架的选择。
这有什么不对?
从表面上看,似乎我们做得非常好,它简洁,易于实现,我们所有的数据都通过密码保护,如果我们改变了前端或后端技术,它仍然可以工作。但是有一些问题。
-
基本身份验证仅限于用户名和密码身份验证。
-
身份验证UI无处不在但很难看(浏览器对话框)。
-
Cross Site Request Forgery(CSRF)不提供任何保护。
CSRF并不是我们的应用程序的问题,因为它只需要获取后端资源(即服务器中没有状态更改)。一旦你在你的应用程序中有POST,PUT或DELETE,任何合理的现代措施都不再安全。
在本系列的下一部分中,我们将扩展应用程序以使用基于表单的身份验证,这比HTTP Basic更灵活。一旦我们有了表单,我们将需要CSRF保护,Spring Security和Angular都有一些很好的开箱即用功能来帮助解决这个问题。剧透:我们将需要使用HttpSession
。
谢谢:我要感谢帮助我开发这个系列的所有人,特别是Rob Winch和Thorsten Spaeth对文本和源代码的仔细审查,以及教我一些技巧,我甚至不知道这些部分我以为我最熟悉。
原文地址:https://spring.io/guides/tutorials/spring-security-and-angular-js
下载代码:https://github.com/daqiang123/Spring-Security-and-Angular/tree/master/basic
依次执行mvn clean,mvn install,mvn spring-boot:run命令,运行程序。
如果执行命令报错,可终止后再次执行。
在浏览器中输入http://localhost:8080/,
在登录框中输入用户名:user,密码:password,访问程序。
欢迎加入大华软件学院QQ群交流,群号:665714453。