Aplicativo front-end com Spring Security OAuth - Fluxo do código de autorização
1. Visão geral
Neste tutorial, continuaremos nossoSpring Security OAuth series construindo um front-end simples para o fluxo do código de autorização.
Lembre-se de que o foco aqui é o cliente; dê uma olhada na redação deSpring REST API + OAuth2 + AngularJS - para revisar a configuração detalhada para os Servidores de Autorização e Recursos.
2. Servidor de Autorização
Antes de chegarmos ao nosso front end, precisamos adicionar os detalhes de nossos clientes em nossa configuração do Authorization Server:
@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/")
...
Observe como agora temos o tipo de concessão de código de autorização ativado, com os seguintes detalhes simples:
-
nosso id de cliente éfooClientId
-
nossos escopos sãofoo,read areiawrite
-
o URI de redirecionamento éhttp://localhost:8089/ (usaremos a porta 8089 para nosso aplicativo front-end)
3. O front end
Agora, vamos começar a construir nosso aplicativo front-end simples.
Como vamos usar o Angular 6 para nosso aplicativo aqui, precisamos usar o plug-infrontend-maven-plugin em nosso aplicativo 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
Observe que, naturalmente, precisamos instalarNode.js primeiro em nossa caixa; usaremos a CLI Angular para gerar a base para nosso aplicativo:
ng novo authCode
4. Módulo Angular
Agora, vamos discutir nosso Módulo Angular em detalhes.
Aqui está nossoAppModule simples:
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 { }
Nosso módulo consiste em três componentes e um serviço, vamos discuti-los nas seções a seguir
4.1. Componente de aplicativo
Vamos começar com nossoAppComponent, que é o componente raiz:
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
template: `
`
})
export class AppComponent {}
4.2. Componente residencial
A seguir está nosso componente 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();
}
}
Observe que:
-
Se o usuário não estiver logado, apenas o botão de login aparecerá
-
O botão de login redireciona o usuário para o URL de autorização
-
Quando o usuário é redirecionado de volta com o código de autorização, recuperamos o token de acesso usando esse código
4.3. Componente Foo
Nosso terceiro e último componente é oFooComponent; isso exibe os recursosFoo - obtidos do servidor de recursos:
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. Serviço de aplicativo
Agora, vamos dar uma olhada emAppService:
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();
}
}
Vamos fazer um resumo rápido de nossa implementação aqui:
-
checkCredentials(): para verificar se o usuário está logado
-
retrieveToken(): para obter o token de acesso usando o código de autorização
-
saveToken(): para salvar o token de acesso em um cookie
-
getResource(): para obter detalhes de Foo usando seu ID
-
logout(): para excluir o cookie do token de acesso
5. Execute o aplicativo
Para executar nosso aplicativo e garantir que tudo esteja funcionando corretamente, precisamos:
-
Primeiro, execute o Authorization Server na porta 8081
-
Em seguida, execute o servidor de recursos na porta 8082
-
Por fim, execute o Front End
Precisamos criar nosso aplicativo primeiro:
mvn clean install
Em seguida, altere o diretório para src / main / resources:
cd src/main/resources
Em seguida, execute nosso aplicativo na porta 8089:
npm start
6. Conclusão
Aprendemos como criar um cliente front-end simples para o fluxo do Código de Autorização usando Spring e Angular 6.
E, como sempre, o código-fonte completo está disponívelover on GitHub.