javascript
angular1.2.27_Angular 8 + Spring Boot 2.2:立即构建一个CRUD应用程序!
angular1.2.27
“我喜歡編寫身份驗(yàn)證和授權(quán)代碼。” ?從來沒有Java開發(fā)人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進(jìn)行托管身份驗(yàn)證,授權(quán)和多因素身份驗(yàn)證。
如果您已經(jīng)成為Java開發(fā)人員超過15年,那么您可能還記得何時(shí)有太多的Java Web框架。 它始于Struts和WebWork。 然后Tapestry,Wicket和JSF出現(xiàn)并倡導(dǎo)基于組件的框架的想法。 Spring MVC于2004年發(fā)布(與Flex 1.0和JSF 1.0同月發(fā)布),并在接下來的六年中成為Java Web框架的實(shí)際標(biāo)準(zhǔn)。
隨之而來的是AngularJS,每個(gè)人都開始將其UI架構(gòu)遷移到JavaScript。 Angular 2是在2014年首次發(fā)布Spring Boot的同時(shí)宣布的,它花了幾年時(shí)間才發(fā)布,固化并成為可行的選擇。 這些天,我們將其稱為Angular,沒有版本號(hào)。 最近的幾個(gè)版本相當(dāng)穩(wěn)定,主要版本之間的升級(jí)路徑很流暢。
今天,我想向您展示如何使用Angular和Spring Boot的最新和最佳版本構(gòu)建應(yīng)用程序。 Angular 8和Spring Boot 2.2都進(jìn)行了性能改進(jìn),以改善開發(fā)人員的生活。
Angular 8有什么新功能?
Angular 8添加了差異加載,一個(gè)可選的Ivy Renderer和Bazel作為構(gòu)建選項(xiàng)。 差異加載是CLI在構(gòu)建已部署應(yīng)用程序的一部分時(shí)構(gòu)建兩個(gè)單獨(dú)的捆綁軟件的地方。 現(xiàn)代捆綁軟件可用于常綠的瀏覽器,而傳統(tǒng)捆綁軟件則包含所有舊瀏覽器所需的polyfill。
Ivy Renderer更小,更快,更易于調(diào)試,改進(jìn)了類型檢查,并且最重要的是向后兼容。
Spring Boot 2.2中有什么新功能?
Spring Boot在快速啟動(dòng)的框架(如Micronaut和Quarkus)中感到有些不適,并且也實(shí)現(xiàn)了許多性能改進(jìn)。 現(xiàn)在默認(rèn)情況下禁用JMX,禁用Hibernate的實(shí)體掃描,并且默認(rèn)情況下啟用Bean的惰性初始化。 另外,通過在Spring Boot的@Configuration類中使用proxyBeanMethods=false減少了啟動(dòng)時(shí)間和內(nèi)存使用量。 有關(guān)更多信息,請(qǐng)參見Spring Boot 2.2 Release Notes 。
如果您使用這些框架的較舊版本,則可能需要查看我以前的幾篇文章:
- 使用Angular 7.0和Spring Boot 2.1構(gòu)建基本的CRUD應(yīng)用
- 使用Angular 5.0和Spring Boot 2.0構(gòu)建基本的CRUD應(yīng)用
這篇文章介紹了如何構(gòu)建一個(gè)簡單的CRUD應(yīng)用程序,該應(yīng)用程序顯示了一系列涼爽的汽車。 它允許您編輯汽車,并顯示與汽車名稱匹配的GIPHY動(dòng)畫gif。 您還將學(xué)習(xí)如何使用Okta的Spring Boot啟動(dòng)程序和Angular SDK保護(hù)應(yīng)用程序的安全。 下面是該應(yīng)用完成時(shí)的屏幕截圖。
您將需要安裝Java 11和Node.js 10+才能完成本教程。
使用Spring Boot 2.2構(gòu)建API
要開始使用Spring Boot 2.2,請(qǐng)轉(zhuǎn)到start.spring.io并創(chuàng)建一個(gè)使用Java 11(在更多選項(xiàng)下),Spring Boot版本2.2.0 M2和依賴項(xiàng)的新項(xiàng)目,以創(chuàng)建安全的API:JPA, H2,Rest Repository,Lombok,Okta和Web。
創(chuàng)建一個(gè)目錄來保存您的服務(wù)器和客戶端應(yīng)用程序。 我叫我的okta-spring-boot-2-angular-8-example ,但是您可以隨便叫什么。
如果您希望應(yīng)用程序正在運(yùn)行而不是編寫代碼,則可以在GitHub上查看示例 ,或使用以下命令在本地克隆并運(yùn)行。
git clone https://github.com/oktadeveloper/okta-spring-boot-2-angular-8-example.git cd okta-spring-boot-2-angular-8-example/client npm install ng serve & cd ../server ./mvnw spring-boot:run從start.spring.io下載demo.zip之后,展開它,然后將demo目錄復(fù)制到您的應(yīng)用程序持有人目錄中。 將demo重命名為server 。 打開server/pom.xml并注釋掉Okta的Spring Boot啟動(dòng)器上的依賴項(xiàng)。
<!--dependency><groupId>com.okta.spring</groupId><artifactId>okta-spring-boot-starter</artifactId><version>1.1.0</version> </dependency-->在您最喜歡的IDE中打開項(xiàng)目,并在src/main/java/com/okta/developer/demo目錄中創(chuàng)建Car.java類。 您可以使用Lombok的注釋來減少樣板代碼。
package com.okta.developer.demo;import lombok.*;import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.Entity;@Entity @Data @NoArgsConstructor public class Car {@Id @GeneratedValueprivate Long id;private @NonNull String name; }創(chuàng)建一個(gè)CarRepository類以對(duì)Car實(shí)體執(zhí)行CRUD(創(chuàng)建,讀取,更新和刪除)。
package com.okta.developer.demo;import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.rest.core.annotation.RepositoryRestResource;@RepositoryRestResource interface CarRepository extends JpaRepository<car, long=""> { } </car,>將ApplicationRunner bean添加到DemoApplication類(在src/main/java/com/okta/developer/demo/DemoApplication.java ),并使用它向數(shù)據(jù)庫添加一些默認(rèn)數(shù)據(jù)。
package com.okta.developer.demo;import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import java.util.stream.Stream;@SpringBootApplication public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@BeanApplicationRunner init(CarRepository repository) {return args -> {Stream.of("Ferrari", "Jaguar", "Porsche", "Lamborghini", "Bugatti","AMC Gremlin", "Triumph Stag", "Ford Pinto", "Yugo GV").forEach(name -> {Car car = new Car();car.setName(name);repository.save(car);});repository.findAll().forEach(System.out::println);};} }如果在添加此代碼后啟動(dòng)應(yīng)用程序(使用./mvnw spring-boot:run ),則會(huì)在啟動(dòng)時(shí)看到控制臺(tái)中顯示的汽車列表。
Car(id=1, name=Ferrari) Car(id=2, name=Jaguar) Car(id=3, name=Porsche) Car(id=4, name=Lamborghini) Car(id=5, name=Bugatti) Car(id=6, name=AMC Gremlin) Car(id=7, name=Triumph Stag) Car(id=8, name=Ford Pinto) Car(id=9, name=Yugo GV)注意:如果看到Fatal error compiling: invalid target release: 11 ,這是因?yàn)槟褂玫氖荍ava8。如果更改為使用Java 11,則該錯(cuò)誤將消失。 如果您使用的是SDKMAN , 請(qǐng)先運(yùn)行sdk install java 11.0.2-open然后運(yùn)行sdk default java 11.0.2-open 。
添加一個(gè)CoolCarController類(在src/main/java/com/okta/developer/demo ),該類返回要在Angular客戶端中顯示的酷車列表。
package com.okta.developer.demo;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Collection; import java.util.stream.Collectors;@RestController class CoolCarController {private CarRepository repository;public CoolCarController(CarRepository repository) {this.repository = repository;}@GetMapping("/cool-cars")public Collection<Car> coolCars() {return repository.findAll().stream().filter(this::isCool).collect(Collectors.toList());}private boolean isCool(Car car) {return !car.getName().equals("AMC Gremlin") &&!car.getName().equals("Triumph Stag") &&!car.getName().equals("Ford Pinto") &&!car.getName().equals("Yugo GV");} }如果重新啟動(dòng)服務(wù)器,并使用瀏覽器或命令行客戶端訪問http://localhost:8080/cool-cars ,則應(yīng)該看到已過濾的汽車列表。
$ http :8080/cool-cars HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Date: Tue, 07 May 2019 18:07:33 GMT Transfer-Encoding: chunked[{"id": 1,"name": "Ferrari"},{"id": 2,"name": "Jaguar"},{"id": 3,"name": "Porsche"},{"id": 4,"name": "Lamborghini"},{"id": 5,"name": "Bugatti"} ]使用Angular CLI創(chuàng)建客戶端
Angular CLI是一個(gè)命令行實(shí)用程序,可以為您生成Angular項(xiàng)目。 它不僅可以創(chuàng)建新項(xiàng)目,而且還可以生成代碼。 這是一個(gè)方便的工具,因?yàn)樗€提供了一些命令,這些命令將生成和優(yōu)化您的項(xiàng)目以進(jìn)行生產(chǎn)。 它使用webpack在后臺(tái)進(jìn)行構(gòu)建。
安裝最新版本的Angular CLI(在撰寫本文時(shí)為8.0.1版)。
npm i -g @angular/cli@8.0.1在創(chuàng)建的傘形目錄中創(chuàng)建一個(gè)新項(xiàng)目。
ng new client --routing --style css --enable-ivy創(chuàng)建客戶端后,導(dǎo)航至其目錄,刪除.git ,然后安裝Angular Material。
cd client rm -rf .git # optional: .git won't be created if you don't have Git installed ng add @angular/material當(dāng)提示您提供主題和其他選項(xiàng)時(shí),請(qǐng)選擇默認(rèn)值。
您將使用Angular Material的組件使UI看起來更好,尤其是在手機(jī)上。 如果您想了解有關(guān)Angular Material的更多信息,請(qǐng)參見material.angular.io 。 它具有有關(guān)其各種組件以及如何使用它們的大量文檔。 右上角的油漆桶將允許您預(yù)覽可用的主題顏色。
使用Angular CLI構(gòu)建汽車列表頁面
使用Angular CLI生成可以與Cool Cars API對(duì)話的汽車服務(wù)。
ng g s shared/car/car更新client/src/app/shared/car/car.service.ts以從服務(wù)器獲取汽車列表。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs';@Injectable({providedIn: 'root' }) export class CarService {constructor(private http: HttpClient) {}getAll(): Observable<any> {return this.http.get('//localhost:8080/cool-cars');} }打開src/app/app.module.ts ,并將HttpClientModule添加為導(dǎo)入。
import { HttpClientModule } from '@angular/common/http';@NgModule({declarations: [AppComponent],imports: [BrowserModule,AppRoutingModule,BrowserAnimationsModule,HttpClientModule],providers: [],bootstrap: [AppComponent] })生成car-list組件以顯示汽車列表。
ng g c car-list更新client/src/app/car-list/car-list.component.ts以使用CarService來獲取列表并在本地cars變量中設(shè)置值。
import { Component, OnInit } from '@angular/core'; import { CarService } from '../shared/car/car.service';@Component({selector: 'app-car-list',templateUrl: './car-list.component.html',styleUrls: ['./car-list.component.css'] }) export class CarListComponent implements OnInit {cars: Array<any>;constructor(private carService: CarService) { }ngOnInit() {this.carService.getAll().subscribe(data => {this.cars = data;});} }更新client/src/app/car-list/car-list.component.html以顯示汽車列表。
<h2>Car List</h2><div *ngFor="let car of cars">{{car.name}} </div>更新client/src/app/app.component.html以具有app-car-list元素。
<div style="text-align:center"><h1>Welcome to {{ title }}!</h1> </div><app-car-list></app-car-list> <router-outlet></router-outlet>使用ng serve -o啟動(dòng)客戶端應(yīng)用程序。 您現(xiàn)在還看不到汽車清單,如果您打開開發(fā)者控制臺(tái),您將明白原因。
發(fā)生此錯(cuò)誤的原因是您尚未在服務(wù)器上啟用CORS(跨源資源共享)。
在服務(wù)器上啟用CORS
要在服務(wù)器上啟用CORS,添加@CrossOrigin注釋到CoolCarController (在server/src/main/java/com/okta/developer/demo/CoolCarController.java )。
import org.springframework.web.bind.annotation.CrossOrigin; ... @GetMapping("/cool-cars") @CrossOrigin(origins = "http://localhost:4200") public Collection<Car> coolCars() {return repository.findAll().stream().filter(this::isCool).collect(Collectors.toList()); }在Spring啟動(dòng)版本2.1.4及以下,你還可以添加一個(gè)@CrossOrigin注釋您CarRepository 。 從Angular添加/刪除/編輯時(shí),這將允許您與其端點(diǎn)進(jìn)行通信。
import org.springframework.web.bind.annotation.CrossOrigin;@RepositoryRestResource @CrossOrigin(origins = "http://localhost:4200") interface CarRepository extends JpaRepository<Car, Long> { }但是,這在Spring Boot 2.2.0.M2中不再起作用 。 好消息是有解決方法。 您可以將CorsFilter bean添加到DemoApplication.java類中。 當(dāng)您還集成Spring Security時(shí),這是必需的。 您只是要早一點(diǎn)做。
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.core.Ordered; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import java.util.Collections;...public class DemoApplication {// main() and init() methods@Beanpublic FilterRegistrationBean<CorsFilter> simpleCorsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true);config.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));config.setAllowedMethods(Collections.singletonList("*"));config.setAllowedHeaders(Collections.singletonList("*"));source.registerCorsConfiguration("/**", config);FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));bean.setOrder(Ordered.HIGHEST_PRECEDENCE);return bean;} }重新啟動(dòng)服務(wù)器,刷新客戶端,您應(yīng)該在瀏覽器中看到汽車列表。
添加角材料
您已經(jīng)安裝了Angular Material,要使用其組件,需要導(dǎo)入它們。 打開client/src/app/app.module.ts并添加動(dòng)畫的導(dǎo)入,以及Material的工具欄,按鈕,輸入,列表和卡片布局。
import { MatButtonModule, MatCardModule, MatInputModule, MatListModule, MatToolbarModule } from '@angular/material';@NgModule({...imports: [BrowserModule,AppRoutingModule,BrowserAnimationsModule,HttpClientModule,MatButtonModule,MatCardModule,MatInputModule,MatListModule,MatToolbarModule],... })更新client/src/app/app.component.html以使用工具欄組件。
<mat-toolbar color="primary"><span>Welcome to {{title}}!</span> </mat-toolbar><app-car-list></app-car-list> <router-outlet></router-outlet>更新client/src/app/car-list/car-list.component.html以使用卡片布局和列表組件。
<mat-card><mat-card-title>Car List</mat-card-title><mat-card-content><mat-list><mat-list-item *ngFor="let car of cars"><img mat-list-avatar src="{{car.giphyUrl}}" alt="{{car.name}}"><h3 mat-line>{{car.name}}</h3></mat-list-item></mat-list></mat-card-content> </mat-card>如果使用ng serve運(yùn)行客戶端并導(dǎo)航到http://localhost:4200 ,則會(huì)看到汽車列表,但沒有與之關(guān)聯(lián)的圖像。
使用Giphy添加動(dòng)畫GIF
要將giphyUrl屬性添加到每輛汽車,請(qǐng)創(chuàng)建client/src/app/shared/giphy/giphy.service.ts并使用以下代碼填充。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { map } from 'rxjs/operators';@Injectable({providedIn: 'root'}) export class GiphyService {// This is a Giphy API Key I created. Create your own at https://developers.giphy.com/dashboard/?create=true.giphyApi = '//api.giphy.com/v1/gifs/search?api_key=nOTRbUNMgD5mj4XowN2ERoPNudAkK6ft&limit=1&q=';constructor(public http: HttpClient) {}get(searchTerm) {const apiLink = this.giphyApi + searchTerm;return this.http.get(apiLink).pipe(map((response: any) => {if (response.data.length > 0) {return response.data[0].images.original.url;} else {return 'https://media.giphy.com/media/YaOxRsmrv9IeA/giphy.gif'; // dancing cat for 404}}));} }更新client/src/app/car-list/car-list.component.ts以在每輛汽車上設(shè)置giphyUrl屬性。
import { Component, OnInit } from '@angular/core'; import { CarService } from '../shared/car/car.service'; import { GiphyService } from '../shared/giphy/giphy.service';@Component({selector: 'app-car-list',templateUrl: './car-list.component.html',styleUrls: ['./car-list.component.css'] }) export class CarListComponent implements OnInit {cars: Array<any>;constructor(private carService: CarService, private giphyService: GiphyService) { }ngOnInit() {this.carService.getAll().subscribe(data => {this.cars = data;for (const car of this.cars) {this.giphyService.get(car.name).subscribe(url => car.giphyUrl = url);}});} }現(xiàn)在,您的瀏覽器將顯示汽車名稱列表以及它們旁邊的頭像圖像。
向您的Angular應(yīng)用添加編輯功能
列出汽車名稱和圖像很酷,但是當(dāng)您可以與其互動(dòng)時(shí),它會(huì)更加有趣! 要添加編輯功能,請(qǐng)首先生成car-edit組件。
ng g c car-edit更新client/src/app/shared/car/car.service.ts以具有添加,移除和更新汽車的方法。 這些方法跟由提供的端點(diǎn)CarRepository及其@RepositoryRestResource注釋。
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs';@Injectable({providedIn: 'root'}) export class CarService {public API = '//localhost:8080';public CAR_API = this.API + '/cars';constructor(private http: HttpClient) {}getAll(): Observable<any> {return this.http.get(this.API + '/cool-cars');}get(id: string) {return this.http.get(this.CAR_API + '/' + id);}save(car: any): Observable<any> {let result: Observable<any>;if (car.href) {result = this.http.put(car.href, car);} else {result = this.http.post(this.CAR_API, car);}return result;}remove(href: string) {return this.http.delete(href);} }在client/src/app/car-list/car-list.component.html ,添加指向編輯組件的鏈接。 另外,在底部添加按鈕以添加新車。
<mat-card><mat-card-title>Car List</mat-card-title><mat-card-content><mat-list><mat-list-item *ngFor="let car of cars"><img mat-list-avatar src="{{car.giphyUrl}}" alt="{{car.name}}"><h3 mat-line><a mat-button [routerLink]="['/car-edit', car.id]">{{car.name}}</a></h3></mat-list-item></mat-list></mat-card-content><button mat-fab color="primary" [routerLink]="['/car-add']">Add</button> </mat-card>在client/src/app/app.module.ts ,導(dǎo)入FormsModule 。
import { FormsModule } from '@angular/forms';@NgModule({...imports: [...FormsModule],... })在client/src/app/app-routing.module.ts ,為CarListComponent和CarEditComponent添加路由。
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { CarListComponent } from './car-list/car-list.component'; import { CarEditComponent } from './car-edit/car-edit.component';const routes: Routes = [{ path: '', redirectTo: '/car-list', pathMatch: 'full' },{path: 'car-list',component: CarListComponent},{path: 'car-add',component: CarEditComponent},{path: 'car-edit/:id',component: CarEditComponent} ];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule] }) export class AppRoutingModule { }修改client/src/app/car-edit/car-edit.component.ts以從URL上傳遞的ID中獲取汽車的信息,并添加保存和刪除方法。
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; import { CarService } from '../shared/car/car.service'; import { GiphyService } from '../shared/giphy/giphy.service'; import { NgForm } from '@angular/forms';@Component({selector: 'app-car-edit',templateUrl: './car-edit.component.html',styleUrls: ['./car-edit.component.css'] }) export class CarEditComponent implements OnInit, OnDestroy {car: any = {};sub: Subscription;constructor(private route: ActivatedRoute,private router: Router,private carService: CarService,private giphyService: GiphyService) {}ngOnInit() {this.sub = this.route.params.subscribe(params => {const id = params.id;if (id) {this.carService.get(id).subscribe((car: any) => {if (car) {this.car = car;this.car.href = car._links.self.href;this.giphyService.get(car.name).subscribe(url => car.giphyUrl = url);} else {console.log(`Car with id '${id}' not found, returning to list`);this.gotoList();}});}});}ngOnDestroy() {this.sub.unsubscribe();}gotoList() {this.router.navigate(['/car-list']);}save(form: NgForm) {this.carService.save(form).subscribe(result => {this.gotoList();}, error => console.error(error));}remove(href) {this.carService.remove(href).subscribe(result => {this.gotoList();}, error => console.error(error));} }更新client/src/app/car-edit/car-edit.component.htmlHTML,以具有帶有汽車名稱的表單,并顯示來自Giphy的圖像。
<mat-card><form #carForm="ngForm" (ngSubmit)="save(carForm.value)"><mat-card-header><mat-card-title><h2>{{car.name ? 'Edit' : 'Add'}} Car</h2></mat-card-title></mat-card-header><mat-card-content><input type="hidden" name="href" [(ngModel)]="car.href"><mat-form-field><input matInput placeholder="Car Name" [(ngModel)]="car.name"required name="name" #name></mat-form-field></mat-card-content><mat-card-actions><button mat-raised-button color="primary" type="submit"[disabled]="!carForm.valid">Save</button><button mat-raised-button color="secondary" (click)="remove(car.href)"*ngIf="car.href" type="button">Delete</button><a mat-button routerLink="/car-list">Cancel</a></mat-card-actions><mat-card-footer><div class="giphy"><img src="{{car.giphyUrl}}" alt="{{car.name}}"></div></mat-card-footer></form> </mat-card>通過將以下CSS添加到client/src/app/car-edit/car-edit.component.css ,在圖像周圍添加一些填充。
.giphy {margin: 10px; }修改client/src/app/app.component.html并刪除<app-car-list></app-car-list> 。
<mat-toolbar color="primary"><span>Welcome to {{title}}!</span> </mat-toolbar><router-outlet></router-outlet>進(jìn)行所有這些更改之后,您應(yīng)該可以添加,編輯或刪除任何汽車。 下面的屏幕快照顯示了帶有添加按鈕的列表。
以下屏幕截圖顯示了編輯已添加的汽車的外觀。
將OIDC身份驗(yàn)證添加到您的Spring Boot + Angular App中
使用OIDC添加身份驗(yàn)證是一個(gè)不錯(cuò)的功能,可以添加到此應(yīng)用程序中。 如果您想添加審核或個(gè)性化您的應(yīng)用程序(例如,使用評(píng)分功能),那么知道此人的身份將非常有用。
Spring安全+ OIDC
在服務(wù)器端,您可以使用Okta的Spring Boot Starter來鎖定一切,它利用了Spring Security及其OIDC支持。 打開server/pom.xml并取消注釋Okta Spring Boot啟動(dòng)器。
<dependency><groupId>com.okta.spring</groupId><artifactId>okta-spring-boot-starter</artifactId><version>1.1.0</version> </dependency>現(xiàn)在,您需要配置服務(wù)器以使用Okta進(jìn)行身份驗(yàn)證。 為此,您需要在Okta中創(chuàng)建OIDC應(yīng)用。
在Okta中創(chuàng)建OIDC應(yīng)用
登錄到您的1563開發(fā)者帳戶(或者注冊(cè) ,如果你沒有一個(gè)帳戶)并導(dǎo)航到應(yīng)用程序 > 添加應(yīng)用程序 。 單擊“ 單頁應(yīng)用程序” ,再單擊“ 下一步” ,然后為應(yīng)用程序命名。 將所有http://localhost:8080實(shí)例更改為http://localhost:4200 ,然后單擊完成 。
您將在頁面底部看到客戶端ID。 將它和issuer屬性添加到server/src/main/resources/application.properties 。
okta.oauth2.client-id={yourClientId} okta.oauth2.issuer=https://{yourOktaDomain}/oauth2/default創(chuàng)建server/src/main/java/com/okta/developer/demo/SecurityConfiguration.java以將您的Spring Boot應(yīng)用配置為資源服務(wù)器。
package com.okta.developer.demo;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;@EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().oauth2ResourceServer().jwt();} }進(jìn)行這些更改之后,您應(yīng)該能夠重新啟動(dòng)應(yīng)用程序,并在嘗試導(dǎo)航到http://localhost:8080時(shí)看到錯(cuò)誤。
注意:您可以通過將http://localhost:8080/login/oauth2/code/okta為應(yīng)用程序的重定向URI來解決此錯(cuò)誤,但這不能解決問題。 如果您想通過Spring Boot支持OIDC登錄,則需要注冊(cè)一個(gè)Web應(yīng)用程序(而不是SPA),并在application.properties包含一個(gè)客戶端密碼。 這不是本教程中的必要步驟。
現(xiàn)在您的服務(wù)器已被鎖定,您需要配置客戶端以使用訪問令牌與之對(duì)話。 這就是Okta的Angular SDK派上用場(chǎng)的地方。
Okta的角度支撐
Okta Angular SDK是Okta Auth JS的包裝,后者基于OIDC。 可以在GitHub上找到有關(guān)Okta的Angular庫的更多信息。
為了簡化Angular SDK的安裝和配置,我們創(chuàng)建了一個(gè)@ oktadev / schematics項(xiàng)目,該項(xiàng)目可以為您完成所有工作。 您可以在“ 使用角度示意圖簡化生活”中閱讀有關(guān)@ oktadev / schematics如何工作的更多信息。
在安裝它之前,最好將您的項(xiàng)目檢查到源代碼管理中。 如果未安裝Git,則可以將項(xiàng)目復(fù)制到另一個(gè)位置作為備份。 如果確實(shí)安裝了Git,請(qǐng)從項(xiàng)目的根目錄中運(yùn)行以下命令。
git init git add . git commit -m "Initialize project"要安裝和配置Okta的Angular SDK,請(qǐng)?jiān)赾lient目錄中運(yùn)行以下命令:
ng add @oktadev/schematics --issuer=https://{yourOktaDomain}/oauth2/default --clientId={yourClientId}該命令將:
- 安裝@okta/okta-angular
- 在auth-routing.module.ts為您的應(yīng)用配置Okta的Angular SDK
- 將isAuthenticated邏輯添加到app.component.ts
- 添加帶有登錄和注銷按鈕的HomeComponent
- 使用到/home的默認(rèn)路由和/implicit/callback路由配置路由
- 添加一個(gè)HttpInterceptor ,該HttpInterceptor向localhost請(qǐng)求添加帶有訪問令牌的Authorization標(biāo)頭
該auth-routing.module.ts文件添加到默認(rèn)路由HomeComponent ,所以你需要?jiǎng)h除默認(rèn)的app-routing.module.ts 。 修改app-routing.module.ts以刪除第一個(gè)路由并添加OktaAuthGuard 。 這樣可以確保在訪問路由之前對(duì)用戶進(jìn)行身份驗(yàn)證。
import { OktaAuthGuard } from '@okta/okta-angular';const routes: Routes = [{path: 'car-list',component: CarListComponent,canActivate: [OktaAuthGuard]},{path: 'car-add',component: CarEditComponent,canActivate: [OktaAuthGuard]},{path: 'car-edit/:id',component: CarEditComponent,canActivate: [OktaAuthGuard]} ];修改client/src/app/app.component.html以使用Material組件并具有一個(gè)注銷按鈕。
<mat-toolbar color="primary"><span>Welcome to {{title}}!</span><span class="toolbar-spacer"></span><button mat-raised-button color="accent" *ngIf="isAuthenticated"(click)="oktaAuth.logout()" [routerLink]="['/home']">Logout</button> </mat-toolbar><router-outlet></router-outlet>您可能會(huì)注意到toolbar-spacer類存在跨度。 要使此功能按預(yù)期工作,請(qǐng)?jiān)赾lient/src/app/app.component.css添加一個(gè)toolbar-spacer規(guī)則。
.toolbar-spacer {flex: 1 1 auto; }然后更新client/src/app/home/home.component.html以使用Angular Material并鏈接到Car List。
<mat-card><mat-card-content><button mat-raised-button color="accent" *ngIf="!isAuthenticated"(click)="oktaAuth.loginRedirect()">Login</button><button mat-raised-button color="accent" *ngIf="isAuthenticated"[routerLink]="['/car-list']">Car List</button></mat-card-content> </mat-card>由于您使用的是HomeComponent Material組件,該組件由新添加的client/src/app/auth-routing.module.ts ,因此需要導(dǎo)入MatButtonModule和MatCardModule 。
import { MatButtonModule, MatCardModule } from '@angular/material';@NgModule({...imports: [...MatButtonModule,MatCardModule],... })要使其內(nèi)容底部沒有底邊框,請(qǐng)通過將以下內(nèi)容添加到client/src/styles.css來使<mat-card>元素填充屏幕。
mat-card {height: 100vh; }現(xiàn)在,如果您重新啟動(dòng)客戶端,一切都應(yīng)該工作。 不幸的是,這不是因?yàn)镮vy尚未實(shí)現(xiàn)CommonJS / UMD支持 。 解決方法是,您可以修改tsconfig.app.json以禁用Ivy。
"angularCompilerOptions": {"enableIvy": false }停止并重新啟動(dòng)ng serve過程。 打開瀏覽器到http://localhost:4200 。
單擊登錄按鈕。 如果一切配置正確,您將被重定向到Okta登錄。
輸入有效的憑據(jù),您應(yīng)該被重定向回您的應(yīng)用程序。 慶祝一切成功! 🎉
了解有關(guān)Spring Boot和Angular的更多信息
跟上快速移動(dòng)的框架(如Spring Boot和Angular)可能很難。 這篇文章旨在讓您快速了解最新版本。 有關(guān)Angular 8的特定更改,請(qǐng)參閱Angular團(tuán)隊(duì)有關(guān)Angular 8版本的博客文章 。 對(duì)于Spring Boot,請(qǐng)參閱其2.2發(fā)行說明 。
您可以在oktadeveloper / okta-spring-boot-2-angular-8-example上的GitHub上看到本教程中開發(fā)的應(yīng)用程序的完整源代碼。
這個(gè)博客有大量的Spring Boot和Angular教程。 這是我的一些最愛:
- 使用Angular和Electron構(gòu)建桌面應(yīng)用程序
- 將您的Spring Boot應(yīng)用程序遷移到最新和最新的Spring Security和OAuth 2.0
- Java 11,Spring Boot和JavaScript中的i18n
- 為Angular應(yīng)用程序建立安全登錄
- 使用Spring WebFlux構(gòu)建React性API
如有任何疑問,請(qǐng)隨時(shí)在下面發(fā)表評(píng)論,或在我們的Okta開發(fā)者論壇上向我們提問。 別忘了在Twitter和YouTube 上關(guān)注我們!
變更日志:
- 2019年6月4日:更新為使用Angular CLI 8.0.1,Angular 8.0.1和Angular Material 8.0.0。 您可以在okta-spring-boot-2-angular-8-example#3中看到示例應(yīng)用程序的更改; 可以在okta.github.io#2911中查看對(duì)此職位的更改。
“ Angular 8 + Spring Boot 2.2:今天就構(gòu)建一個(gè)CRUD應(yīng)用程序!” 最初于2019年5月13日發(fā)布在Okta開發(fā)人員博客上。
“我喜歡編寫身份驗(yàn)證和授權(quán)代碼。” ?從來沒有Java開發(fā)人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進(jìn)行托管身份驗(yàn)證,授權(quán)和多因素身份驗(yàn)證。
翻譯自: https://www.javacodegeeks.com/2019/06/angular-spring-boot-build-crud-app-today-2.html
angular1.2.27
總結(jié)
以上是生活随笔為你收集整理的angular1.2.27_Angular 8 + Spring Boot 2.2:立即构建一个CRUD应用程序!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全文打印什么快捷键(打印文本快捷键)
- 下一篇: adf.test_在ADF 12.2.1