Front-End-App mit Spring Security OAuth - Berechtigungscode-Fluss
1. Überblick
In diesem Tutorial setzen wir unsereSpring Security OAuth series fort, indem wir ein einfaches Frontend für den Ablauf des Autorisierungscodes erstellen.
Denken Sie daran, dass der Fokus hier auf der Client-Seite liegt. Schauen Sie sich die Beschreibung vonSpring REST API + OAuth2 + AngularJSan, um die detaillierte Konfiguration für Autorisierungs- und Ressourcenserver zu überprüfen.
2. Autorisierungsserver
Bevor wir unser Front-End erreichen, müssen wir unsere Client-Details in unserer Authorization Server-Konfiguration hinzufügen:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("fooClientId")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("authorization_code")
.scopes("foo", "read", "write")
.redirectUris("http://localhost:8089/")
...
Beachten Sie, wie wir jetzt den Berechtigungscode-Grant-Typ aktiviert haben, mit den folgenden einfachen Details:
-
Unsere Kunden-ID lautetfooClientId
-
Unsere Bereiche sindfoo,read andwrite
-
Der Umleitungs-URI isthttp://localhost:8089/ (wir werden Port 8089 für unsere Front-End-App verwenden).
3. Das Frontend
Beginnen wir jetzt mit der Erstellung unserer einfachen Front-End-Anwendung.
Da wir hier Angular 6 für unsere App verwenden werden, müssen wir dasfrontend-maven-plugin-Plugin in unserer Spring Boot-Anwendung verwenden:
com.github.eirslett
frontend-maven-plugin
1.6
v8.11.3
6.1.0
src/main/resources
install node and npm
install-node-and-npm
npm install
npm
npm run build
npm
run build
Beachten Sie, dass wir natürlich zuerstNode.js auf unserer Box installieren müssen. Wir verwenden die Angular-CLI, um die Basis für unsere App zu generieren:
ng new authCode
4. Winkelmodul
Lassen Sie uns nun unser Winkelmodul im Detail diskutieren.
Hier sind unsere einfachenAppModule:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { HomeComponent } from './home.component';
import { FooComponent } from './foo.component';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
FooComponent
],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' }], {onSameUrlNavigation: 'reload'})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Unser Modul besteht aus drei Komponenten und einem Service. Wir werden sie in den folgenden Abschnitten behandeln
4.1. App-Komponente
Beginnen wir mit unserenAppComponent, der Stammkomponente:
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
template: `
`
})
export class AppComponent {}
4.2. Hauptkomponente
Als nächstes kommt unsere HauptkomponenteHomeComponent:
import {Component} from '@angular/core';
import {AppService} from './app.service'
@Component({
selector: 'home-header',
providers: [AppService],
template: `
`
})
export class HomeComponent {
public isLoggedIn = false;
constructor(
private _service:AppService){}
ngOnInit(){
this.isLoggedIn = this._service.checkCredentials();
let i = window.location.href.indexOf('code');
if(!this.isLoggedIn && i != -1){
this._service.retrieveToken(window.location.href.substring(i + 5));
}
}
login() {
window.location.href = 'http://localhost:8081/spring-security-oauth-server/oauth/authorize?response_type=code&client_id=' + this._service.clientId + '&redirect_uri='+ this._service.redirectUri;
}
logout() {
this._service.logout();
}
}
Beachten Sie, dass:
-
Wenn der Benutzer nicht angemeldet ist, wird nur die Anmeldeschaltfläche angezeigt
-
Die Anmeldeschaltfläche leitet den Benutzer zur Autorisierungs-URL weiter
-
Wenn der Benutzer mit dem Autorisierungscode zurückgeleitet wird, rufen wir das Zugriffstoken mit diesem Code ab
4.3. Foo-Komponente
Unsere dritte und letzte Komponente istFooComponent; Hier werden die Ressourcen vonFooangezeigt, die vom Ressourcenserver bezogen wurden:
import { Component } from '@angular/core';
import {AppService, Foo} from './app.service'
@Component({
selector: 'foo-details',
providers: [AppService],
template: `
Foo Details
{{foo.id}}
{{foo.name}}
`
})
export class FooComponent {
public foo = new Foo(1,'sample foo');
private foosUrl = 'http://localhost:8082/spring-security-oauth-resource/foos/';
constructor(private _service:AppService) {}
getFoo(){
this._service.getResource(this.foosUrl+this.foo.id)
.subscribe(
data => this.foo = data,
error => this.foo.name = 'Error');
}
}
4.4. App-Service
Schauen wir uns nun dieAppService an:
import {Injectable} from '@angular/core';
import { Cookie } from 'ng2-cookies';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
export class Foo {
constructor(
public id: number,
public name: string) { }
}
@Injectable()
export class AppService {
public clientId = 'fooClientId';
public redirectUri = 'http://localhost:8089/';
constructor(
private _http: HttpClient){}
retrieveToken(code){
let params = new URLSearchParams();
params.append('grant_type','authorization_code');
params.append('client_id', this.clientId);
params.append('redirect_uri', this.redirectUri);
params.append('code',code);
let headers = new HttpHeaders({'Content-type': 'application/x-www-form-urlencoded; charset=utf-8', 'Authorization': 'Basic '+btoa(this.clientId+":secret")});
this._http.post('http://localhost:8081/spring-security-oauth-server/oauth/token', params.toString(), { headers: headers })
.subscribe(
data => this.saveToken(data),
err => alert('Invalid Credentials')
);
}
saveToken(token){
var expireDate = new Date().getTime() + (1000 * token.expires_in);
Cookie.set("access_token", token.access_token, expireDate);
console.log('Obtained Access token');
window.location.href = 'http://localhost:8089';
}
getResource(resourceUrl) : Observable{
var headers = new HttpHeaders({'Content-type': 'application/x-www-form-urlencoded; charset=utf-8', 'Authorization': 'Bearer '+Cookie.get('access_token')});
return this._http.get(resourceUrl,{ headers: headers })
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
checkCredentials(){
return Cookie.check('access_token');
}
logout() {
Cookie.delete('access_token');
window.location.reload();
}
}
Lassen Sie uns hier einen kurzen Überblick über unsere Implementierung geben:
-
checkCredentials(): um zu überprüfen, ob der Benutzer angemeldet ist
-
retrieveToken(): Zum Abrufen des Zugriffstokens mithilfe des Autorisierungscodes
-
saveToken(): Zum Speichern des Zugriffstokens in einem Cookie
-
getResource(): um Foo-Details anhand seiner ID abzurufen
-
logout(): Zum Löschen des Access Token-Cookies
5. Führen Sie die Anwendung aus
Um unsere Anwendung auszuführen und sicherzustellen, dass alles ordnungsgemäß funktioniert, müssen wir:
-
Führen Sie zunächst Authorization Server auf Port 8081 aus
-
Führen Sie dann den Resource Server auf Port 8082 aus
-
Führen Sie schließlich das Front-End aus
Wir müssen zuerst unsere App erstellen:
mvn clean install
Wechseln Sie dann in das Verzeichnis src / main / resources:
cd src/main/resources
Dann starte unsere App auf Port 8089:
npm start
6. Fazit
Wir haben gelernt, wie Sie mit Spring und Angular 6 einen einfachen Front-End-Client für den Authorization Code Flow erstellen.
Und wie immer ist der vollständige Quellcodeover on GitHub verfügbar.