神刀安全网

协作翻译 | Spring Security 和 Angular JS

受保护的单页面应用程序

这一节我们要展示将Spring Security、Spring Boot和Angular JS放在一起使用的一些不错的特性,它们能提供令人愉快且安全的用户体验。对于Spring和Angular JS的初学者而言易于上手,而且也能为专家们所用。这实际上是有关于Spring Security和Angular JS的一系列文章的首篇,成功地对新特性进行了逐一的阐述。我们将会在第二阶段以及后续阶段中对应用程序进行提升,不过伺此后的主要变化是架构上的,而不是功能方面的。

Spring 和单页面应用程序

HTML5,丰富的基于浏览器的特性,以及“单页面应用程序”对于现代开发者而言都是极具价值的工具,但任何具备实际意义的交互都将涉及到后台服务器,静态内容 (HTML, CSS 和 JavaScript)也是如此,因而 我们将需要一个后台服务器。后台服务器可以扮演大量的角色:托管静态内容,有时(不过如今不是那么频繁了)渲染动态的HTML,对用户进行认证,为需要受到保护的资源提供安全访问机制,还有(最后但并不代表最不重要的一个) 就是在浏览器中通过HTTP和JSON(有时也被称作REST API )同JavaScript进行交互。

Spring 一向是用来构建后台功能(特别是在企业级领域中)的流行技术,而随着 Spring Boot 这样的事物的出现,这方面的工作变得从未如此简单。让我们来看看如何使用Spring Boot、Angular JS以及Twitter 的Bootstrap 从零开始去构建一个新的单页面应用程序。选择这一技术栈并没有特殊原因,不过是因为相当流行,尤其是核心Spring在企业级Java市场深受青睐, 因此值得将其作为起点。

创建一个新工程

我们准备逐步完成这个应用程序的创建过程,并进行一些详细描述,因此那些并不完全了解 Spring 和 Angular 的人也可以跟着一起搞清楚。如果你更愿意省掉这个环节,可以跳到最后,应用程序可以运作起来了,来看看所有的东西是如何契合到一起的。创建一个新工程有多种不同的选择:

完整的工程源代码在 Github 上, 因此你可以克隆该工程,然后直接从你喜欢的地方开始。然后跳到下一节。

使用 Curl

创建新工程的最简单方式就是通过 Spring Boot Initializr . 例如,在类Unix系统上使用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" 和 "Security", 然后在 "Generate Project" 点击就行了。zip文件的跟目录中包含了一个标准的 Maven 或者 Gradle 工程, 所以你可以在解压之前先创建一个空目录。然后跳转到下一节。

使用 Spring Tool Suite

Spring Tool Suite ( 一个 Eclipse 插件的集合) 中,你也能够利用一个位于 File->New->Spring Starter Project 的对话框创建和导入工程。然后跳转到下一节。

添加一个主页

单页面应用程序的核心就是一个静态的"index.html", 所以我们首先来创建一个 (在 "src/main/resources/static" 或者 "src/main/resources/public" 中):

index.html

<!doctype html> <html> <head> <title>Hello AngularJS</title> <link href="css/angular-bootstrap.css" rel="stylesheet"> <style type="text/css"> [ng/:cloak], [ng-cloak], .ng-cloak {   display: none !important; } </style> </head>  <body ng-app="hello">   <div class="container">     <h1>Greeting</h1>     <div ng-controller="home" ng-cloak class="ng-cloak">       <p>The ID is {{greeting.id}}</p>       <p>The content is {{greeting.content}}</p>     </div>   </div>   <script src="js/angular-bootstrap.js" type="text/javascript"></script>   <script src="js/hello.js"></script> </body> </html>

这个文件简短得可爱,因为它只是说了句 "Hello World"。

主页的特性

重要的特性包括:

  • 一些在<head>中引入的CSS,为一个还不存在的文件放置的占位符, 不过进行了富有含义的命名("angular-bootstrap.css") 还有一个定义在 "ng-cloak" 类中的内联样式表。

  • "ng-cloak" 类被应用于内容<div>,如此内容就可以一直隐藏知道Angular JS有机会对其进行处理 (这就在初始化页面加载期间的"闪烁")。

  • <body> 被标记为 ng-app="hello" ,其意义就是我们需要定义一个JavaScript模块,Angular就会将其识别为一个叫做"hello"的应用程序。

  • 所有的CSS类(除开"ng-cloak"之外的)都来自 Twitter Bootstrap 。只要我们正确设置好样式表,它们就能让东西变得美观起来。

  • 问候语的内容是使用双中括弧对来标识的, 例如 {{greeting.content}},这样稍后就会有Angular (根据外围的<div>上的ng-controller指令,使用的是一个叫做“home" 的 "控制器")对其进行过滤。

  • Angular JS (以及Twitter Bootstrap) 是在<body>的底部引入的,那样浏览器就可以在处理之前先处理所有的HTML。

  • 我们还引入了一个单独的 "hello.js",这里是我们定义应用程序行为的地方.

我们准备在稍后创建脚本和样式表资源,但现在我们可以忽视掉它们还不存在的事实。

运行应用程序

等你添加好了主页文件,应用程序就可以在一个浏览器中被加载了(竟然它还并不能做太多事情)。你可以在命令行上面这样做:

$ mvn spring-boot:run

然后在浏览器中访问 http://localhost:8080 。 当你加载主页时,应该会遇到一个浏览器对话框,要求输入用户名和密码 (用户名就是 "user",而密码则会在启动时打印在控制台日志中)。因为实际上还没有任何内容,因此在成功的通过了认证之后,你应该会得到一个空白的页面,只会显示一个"Greeting"(问候语)标题。

如果你不喜欢在控制台日志里寻找密码,只要在 "application.properties" ("src/main/resources"目录下)添加上这个就行了: security.user.password=password (并且选择使用你自己的密码)。我们在示例代码中利用 "application.yml" 这样做过。

在IDE中,只要在应用程序类中运行main()方法(只有一个类,如果你使用的是上述的“crul”命令,它就是被叫做 UiApplication)就行了。

要打包和运行一个单独的JAR包的话,你可以这样做:

$ mvn package $ java -jar target/*.jar

前端资源

Angular和其它前端技术的入门级教程经常从互联网直接引用前端库的资源(例如. Angular JS 网站 自己就推荐从  Google CDN 下载资源)。我们不会这样做,而是会通过将几个来自于这种库的文件结合起来,生成 "angular-bootstrap.js" 这个资源。要使得应用程序运行起来,这样做并不是严格必要的,不过这样做对于生产环境上的应用程序而言,通过整合脚本来避免浏览器和服务器间(或者内容分发网络上)的过于频繁的访问,不失为一个最佳实践。因为我们不要对CSS样式表进行修改或者定制,因此也没必要生成 "angular-bootstrap.css" 了, 而我们也可以就只利用来自资源Google CDN的静态资源就行了。不过,在实际的应用程序我我们几乎肯定会希望去修改样式表,并且我们应该不会想手工地区修改CSS资源,因此我们会使用一种更高级的工具(例如.  Less 或者  Sass ), 因此我们也准备要使用一个。

有很多方法可以实现目的,但就此节的目的而言,我们将使用 wro4j , 它是一个基于Java的技术链,用来对前端资源进行预处理和打包。可以将其作为一个JIT(即时)过滤器(Filter)用在任何Servlet应用程序中, 而它也能很好的支持像Maven和Eclipse这样的构建工具,我们也正是要这样使用它。于是我们将要去构建静态资源文件,并将它们打包到应用程序的JAR包中。

旁白: 对于首席(hard-core)前端开发人员而言,Wro4j 可能不是其选择 – 他们应该会使用基于node的工具链, bower 和/或者  grunt 。这些也是相当优秀的工具,而且在互联网上的资料也很全面, 所以如果你想用的话尽管用就是了。如果你只是将这些工具的输出放到 "src/main/resources/static"中,那么完全会起作用。我觉得wro4j方便是因为我并非首席前端开发人员,并且我也知道如何使用基于Java的工具。

为了在编译时创建静态资源,我们往Maven的pom.xml添加了一些魔法 (它相当的冗长,但是是样板化的,因此在Maven中它可以被提炼到一个父pom中去, 或者是在Gradle中的一个共享任务或者插件):

pom.xml

<build>   <resources>     <resource>       <directory>${project.basedir}/src/main/resources</directory>     </resource>     <resource>       <directory>${project.build.directory}/generated-resources</directory>     </resource>   </resources>   <plugins>     <plugin>       <groupId>org.springframework.boot</groupId>       <artifactId>spring-boot-maven-plugin</artifactId>     </plugin>     <plugin>       <artifactId>maven-resources-plugin</artifactId>       <executions>         <execution>           <!-- Serves *only* to filter the wro.xml so it can get an absolute             path for the project -->           <id>copy-resources</id>           <phase>validate</phase>           <goals>             <goal>copy-resources</goal>           </goals>           <configuration>             <outputDirectory>${basedir}/target/wro</outputDirectory>             <resources>               <resource>                 <directory>src/main/wro</directory>                 <filtering>true</filtering>               </resource>             </resources>           </configuration>         </execution>       </executions>     </plugin>     <plugin>       <groupId>ro.isdc.wro4j</groupId>       <artifactId>wro4j-maven-plugin</artifactId>       <version>1.7.6</version>       <executions>         <execution>           <phase>generate-resources</phase>           <goals>             <goal>run</goal>           </goals>         </execution>       </executions>       <configuration>         <wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory</wroManagerFactory>         <cssDestinationFolder>${project.build.directory}/generated-resources/static/css</cssDestinationFolder>         <jsDestinationFolder>${project.build.directory}/generated-resources/static/js</jsDestinationFolder>         <wroFile>${project.build.directory}/wro/wro.xml</wroFile>         <extraConfigFile>${basedir}/src/main/wro/wro.properties</extraConfigFile>         <contextFolder>${basedir}/src/main/wro</contextFolder>       </configuration>       <dependencies>         <dependency>           <groupId>org.webjars</groupId>           <artifactId>jquery</artifactId>           <version>2.1.1</version>         </dependency>         <dependency>           <groupId>org.webjars</groupId>           <artifactId>angularjs</artifactId>           <version>1.3.8</version>         </dependency>         <dependency>           <groupId>org.webjars</groupId>           <artifactId>bootstrap</artifactId>           <version>3.2.0</version>         </dependency>       </dependencies>     </plugin>   </plugins> </build>

你可以逐行复制到你的POM中去,或者如果对 Github中的资源 正一直关注的话,可以就只上扫上一眼。要点是:

  • 我们引入了一些网页jar包作为依赖(jquery 和 bootstrap 用于CSS和样式, 还有Angular JS 用于业务逻辑)。在这些jar文件中的一些静态资源将会被引入到我们生成的"angular-bootstrap.*" 文件中,而jar文件本身并不需要同应用程序一起打包。

  • Twitter Bootstrap 对 jQuery有依赖,因此我们也对其进行了引用。一个没有使用到Bootstrap的AngularJS应用程序不会需要,因为需要来自于jQuery的功能特性,Angular尤其自己的版本。

  • 生成的资源会放到 "target/generated-resources" 中, 而且因为被声明到了 <resources/> 中,它们会被打包到项目的输出的JAR包, 并且在IDE中的类路径(classpath)中可用(只要我们使用了Maven相关的工具,例如Eclipse的m2e)。

  • wro4j-maven-plugin 拥有一些集成到Eclipse的功能,可以从Eclipse Marketplace出对其进行安装 (如果这是第一次遇到,那稍后再去尝试——它对于完成这个应用程序并不是必须的)。如果你安装了的话,那么Eclipse会盯着这些资源文件,并且如果它们发生了变化,那么就会重新生成输出。如果你是以调试模式运行的,那么改变就可以在浏览器中立即重新载入。

  • Wro4j 是受制于一个XML配置文件的,这个配置文件并不知道你的构建类路径,只知道绝对的文件路径,因此我们得创建一个绝对文件路径并将其插入wro.xml中。为此我们会使用Maven资源过滤,而这就是为什么会有一个明确的 "maven-resources-plugin" 声明。

这就是我们需要对POM进行的全部修改。它仍然要添加wro4j构建文件,这个我们所指定的文件将位于 "src/main/wro" 中。

Wro4j 源代码

如果你看看 Github 上的源代码,你只会看到3个文件 (而且其中一个还是空着的,准备后续的定制):

  • wro.properties 是一个面向wro4j中预处理和渲染引擎的配置文件。你可以用它来在工具链的不同部分进行切换。在这种情况下我们用它来从 Less 编译出CSS,并且对 JavaScript 进行压缩, 最终将我们需要的所有的库的源文件结合到两个文件中。

    wro.properties

    preProcessors=lessCssImport postProcessors=less4j,jsMin
  • wro.xml 声明了单独“一组”叫做 "angular-bootstrap" 的资源, 而这最终就是我们所生成的静态资源的基础名称。它包含了对我们所添加的web jar包中的<css>和<js>,还有一个本地资源文件filemain.less引用。

    wro.xml

    <groups xmlns="http://www.isdc.ro/wro">   <group name="angular-bootstrap">   <css>webjar:bootstrap/3.2.0/less/bootstrap.less</css>     <css>file:${project.basedir}/src/main/wro/main.less</css>     <js>webjar:jquery/2.1.1/jquery.min.js</js>     <js>webjar:angularjs/1.3.8/angular.min.js</js>   </group> </groups>
  • main.less 在示例代码中是空的, 它可以被用来定制外观,改变Twitter Bootstrap中的默认设置。例如:为了将默认颜色从蓝色改变成亮粉色,加上一行代码就行了:

    main.less

    @brand-primary: #de8579;

将这些文件复制到你的项目中并运行 "mvn package",然后你就会看到 "bootstrap-angular.*" 资源文件出现在你的JAR文件中。如果你现在就运行app,应该会看到CSS的效果,不过业务逻辑和导航仍然是没有的。

创建Angular应用程序

让我们来创建一个“hello”应用程序 (在 "src/main/resources/static/js/hello.js" 中,那可以在“index.html”底部的<script/>正确的位置找到它了。

最简单的一个AngularJS应用程序如下:

hello.js

angular.module('hello', [])   .controller('home', function($scope) {     $scope.greeting = {id: 'xxx', content: 'Hello World!'} })

应用程序的名称为 "hello",而它有一个空的(而且是多余的) "配置(config)", 还有一个叫做“home”的空“控制器(controller)"。"home" 控制器会在我们载入”index.html“时被调用,因为我们已经用 ng-controller="home" 对内容div进行了装饰。

注意我们将一个神奇的 $scope 注入到了控制器函数 (Angular 通过命名约定来做依赖注入 , 并且会对函数参数的名称进行识别)注入了进去。$scope 随后会用于函数中去设置控制器所负责的UI元素的内容和行为。

如果你在 "src/main/resources/static/js"下面添加那个文件,你的app现在就会是安全并且实用的,它会显示 "Hello World!"。这个是有HTML中的Angular实用占位符 {{greeting.id}} 以及 {{greeting.content}} 来进行渲染的。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 协作翻译 | Spring Security 和 Angular JS

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址