Application front-end avec Spring Security OAuth - Flux de codes d'autorisation
1. Vue d'ensemble
Dans ce didacticiel, nous allons poursuivre nosSpring Security OAuth series en créant une interface simple pour le flux de code d'autorisation.
Gardez à l'esprit que l'accent est mis ici sur le côté client; jetez un œil à l'écriture deSpring REST API + OAuth2 + AngularJS - pour passer en revue la configuration détaillée des serveurs d'autorisation et de ressources.
2. Serveur d'autorisation
Avant de commencer, nous devons ajouter les détails de notre client dans la configuration de notre serveur d'autorisations:
@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/")
...
Notez que le type d’octroi de code d’autorisation est maintenant activé, avec les détails simples suivants:
-
notre identifiant client estfooClientId
-
nos portées sontfoo,read andwrite
-
l'URI de redirection esthttp://localhost:8089/ (nous allons utiliser le port 8089 pour notre application frontale)
3. Le front end
Maintenant, commençons à créer notre application frontale simple.
Comme nous allons utiliser Angular 6 pour notre application ici, nous devons utiliser le pluginfrontend-maven-plugin dans notre application Spring Boot:
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
Notez que, naturellement, nous devons d'abord installerNode.js sur notre box; nous utiliserons la CLI angulaire pour générer la base de notre application:
ng new authCode
4. Module angulaire
Maintenant, parlons de notre module angulaire en détail.
Voici nos simplesAppModule:
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 { }
Notre module se compose de trois composants et d'un service, nous en discuterons dans les sections suivantes
4.1. Composant d'application
Commençons par notreAppComponent qui est le composant racine:
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
template: `
`
})
export class AppComponent {}
4.2. Composant maison
Vient ensuite notre composant principal,HomeComponent:
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();
}
}
Notez que:
-
Si l'utilisateur n'est pas connecté, seul le bouton de connexion apparaîtra
-
Le bouton de connexion redirige l'utilisateur vers l'URL d'autorisation
-
Lorsque l'utilisateur est redirigé avec le code d'autorisation, nous récupérons le jeton d'accès à l'aide de ce code
4.3. Composant Foo
Notre troisième et dernier composant est leFooComponent; cela affiche les ressourcesFoo - obtenues à partir du serveur de ressources:
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. Service d'application
Voyons maintenant lesAppService:
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();
}
}
Faisons un bref aperçu de notre mise en œuvre ici:
-
checkCredentials(): pour vérifier si l'utilisateur est connecté
-
retrieveToken(): pour obtenir un jeton d'accès à l'aide du code d'autorisation
-
saveToken(): pour enregistrer le jeton d'accès dans un cookie
-
getResource(): pour obtenir les détails de Foo en utilisant son ID
-
logout(): pour supprimer le cookie de jeton d'accès
5. Lancer l'application
Pour exécuter notre application et vous assurer que tout fonctionne correctement, nous devons:
-
Tout d'abord, exécutez Authorization Server sur le port 8081.
-
Ensuite, exécutez le serveur de ressources sur le port 8082.
-
Enfin, lancez le Front End
Nous devrons d'abord créer notre application:
mvn clean install
Puis changez de répertoire en src / main / resources:
cd src/main/resources
Ensuite, lancez notre application sur le port 8089:
npm start
6. Conclusion
Nous avons appris à créer un client frontal simple pour le flux de codes d'autorisation à l'aide de Spring et Angular 6.
Et, comme toujours, le code source complet est disponibleover on GitHub.