en este ejemplo, foto es el campo leido de mysql, tiene un atributo data que es la imagen codificada.
var preview = document.querySelector('img');
var arrayBufferView = new Uint8Array(foto.data);
var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
var urlCreator = window.URL;
var imageUrl = urlCreator.createObjectURL(blob);
preview.src = imageUrl;
Validaciones custom con Angular 5
app.component.html
<form [formGroup]="agendaForm" (ngSubmit)="submit()">
<input formControlName="usuario">
<input formControlName="telefono">
<div *ngIf="agendaForm.get('usuario').errors">
<div *ngIf="agendaForm.get('usuario').errors['required']">
Nombre de usuario es requerido
</div>
</div>
<div *ngIf="!agendaForm.valid">
Hay errores en el form!!!
</div>
</form>
app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormControl, ValidatorFn, AbstractControl } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
agendaForm: FormGroup;
constructor(private fb: FormBuilder) {
this.crearForm();
}
crearForm() {
this.agendaForm = this.fb.group({
usuario: ['texto precargado', Validators.required],
telefono: ['', Validators.compose(
[Validators.required,
this.telefonoValidator(/^[679]{1}[0-9]{8}$/)
]
)
]
});
}
telefonoValidator(telefonoExp: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const telefono = telefonoExp.test(control.value);
return !telefono ? {'telefonoNumber': {value: control.value}} : null;
};
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Crear formulario con FormBuilder ReactiveForms en Angular 5
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormControl, ValidatorFn, AbstractControl } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
loginForm: FormGroup;
constructor(private fb: FormBuilder) {
this.crearForm();
}
crearForm() {
this.loginForm = this.fb.group({
usuario: ['texto precargado', Validators.required],
password: ['']
});
}
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormControl, ValidatorFn, AbstractControl } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
loginForm: FormGroup;
constructor(private fb: FormBuilder) {
this.crearForm();
}
crearForm() {
this.loginForm = this.fb.group({
usuario: ['texto precargado', Validators.required],
password: ['']
});
}
}
app.component.html
<form [formGroup]="loginForm" (ngSubmit)="submit()">
<input formControlName="usuario">
<input formControlName="password">
<button type="submit" [disabled]="!loginForm.valid">Enviar</button>
</form>
Subir archivos junto a otros campos en Angular y NodeJS [** 100% OK **]
setup inicial:
npm install --save express body-parser multer fs path
frontend:
app.component.html
<img src="" name="img" />
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div>
<label for="nombre">Name</label>
<input type="text" id="nombre" placeholder="Ingrese el nombre" formControlName="nombre">
</div>
<div>
<label for="foto">Foto</label>
<input type="file" id="foto" (change)="onFileChange($event)" #fileInput>
<button type="button" (click)="clearFile()">clear file</button>
</div>
<button type="submit" [disabled]="form.invalid || loading">Submit</button>
</form>
app.component.ts
import { Component, ElementRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from "@angular/common/http";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
form: FormGroup;
loading: boolean = false;
@ViewChild('fileInput') fileInput: ElementRef;
constructor(private fb: FormBuilder, private http: HttpClient) {
this.createForm();
}
createForm() {
this.form = this.fb.group({
nombre: ['', Validators.required],
foto: null
});
}
onFileChange(event) {
if(event.target.files.length > 0) {
let file = event.target.files[0];
this.form.get('foto').setValue(file);
var preview = document.querySelector('img');
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
}
onSubmit() {
let formModel = new FormData();
formModel.append('nombre', this.form.get('nombre').value);
formModel.append('foto', this.form.get('foto').value);
this.loading = true;
this.http.post("http://localhost:8080/upload", formModel).subscribe((datos) => {
console.log(datos);
});
}
clearFile() {
this.form.get('foto').setValue(null);
this.fileInput.nativeElement.value = '';
}
}
servidor:
var express = require("express")
app = express(),
bodyParser = require("body-parser"),
multer = require('multer'),
fs = require('fs'),
path = require('path');
var upload = multer({ storage: multer.memoryStorage() });
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var router = express.Router();
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use(router);
router.post('/upload', upload.array('foto'), function(req, res) {
console.log("archivos son........: " + req.files);
console.log(req.files[0]);
console.log("el nombre es: " + req.body.nombre);
var buffer = req.files[0].buffer;
var magic = buffer.toString('hex', 0, 4);
var filename = req.files[0].fieldname + '-' + Date.now() + path.extname(req.files[0].originalname);
fs.writeFile('/temp/' + filename, buffer, 'binary', function (err) {
if (err) throw err
res.end('File is uploaded')
})
res.send(JSON.stringify({resultado : 'ok'}));
});
app.listen(8080, function() {
console.log("Node server running on http://localhost:8080");
});
npm install --save express body-parser multer fs path
frontend:
app.component.html
<img src="" name="img" />
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div>
<label for="nombre">Name</label>
<input type="text" id="nombre" placeholder="Ingrese el nombre" formControlName="nombre">
</div>
<div>
<label for="foto">Foto</label>
<input type="file" id="foto" (change)="onFileChange($event)" #fileInput>
<button type="button" (click)="clearFile()">clear file</button>
</div>
<button type="submit" [disabled]="form.invalid || loading">Submit</button>
</form>
app.component.ts
import { Component, ElementRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from "@angular/common/http";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
form: FormGroup;
loading: boolean = false;
@ViewChild('fileInput') fileInput: ElementRef;
constructor(private fb: FormBuilder, private http: HttpClient) {
this.createForm();
}
createForm() {
this.form = this.fb.group({
nombre: ['', Validators.required],
foto: null
});
}
onFileChange(event) {
if(event.target.files.length > 0) {
let file = event.target.files[0];
this.form.get('foto').setValue(file);
var preview = document.querySelector('img');
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
}
onSubmit() {
let formModel = new FormData();
formModel.append('nombre', this.form.get('nombre').value);
formModel.append('foto', this.form.get('foto').value);
this.loading = true;
this.http.post("http://localhost:8080/upload", formModel).subscribe((datos) => {
console.log(datos);
});
}
clearFile() {
this.form.get('foto').setValue(null);
this.fileInput.nativeElement.value = '';
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule, Http } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from "@angular/common/http";
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
HttpModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
servidor:
var express = require("express")
app = express(),
bodyParser = require("body-parser"),
multer = require('multer'),
fs = require('fs'),
path = require('path');
var upload = multer({ storage: multer.memoryStorage() });
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var router = express.Router();
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use(router);
router.post('/upload', upload.array('foto'), function(req, res) {
console.log("archivos son........: " + req.files);
console.log(req.files[0]);
console.log("el nombre es: " + req.body.nombre);
var buffer = req.files[0].buffer;
var magic = buffer.toString('hex', 0, 4);
var filename = req.files[0].fieldname + '-' + Date.now() + path.extname(req.files[0].originalname);
fs.writeFile('/temp/' + filename, buffer, 'binary', function (err) {
if (err) throw err
res.end('File is uploaded')
})
res.send(JSON.stringify({resultado : 'ok'}));
});
app.listen(8080, function() {
console.log("Node server running on http://localhost:8080");
});
Preview image con html5 y filereader y html5
html:
<img src="" name="img" />
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="file" id="avatar" (change)="onFileChange($event)" #fileInput>
<button type="submit">Submit</button>
</form>
Angular:
onFileChange(event) {
if(event.target.files.length > 0) {
let file = event.target.files[0];
var preview = document.querySelector('img');
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
}
<img src="" name="img" />
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input type="file" id="avatar" (change)="onFileChange($event)" #fileInput>
<button type="submit">Submit</button>
</form>
Angular:
onFileChange(event) {
if(event.target.files.length > 0) {
let file = event.target.files[0];
var preview = document.querySelector('img');
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
}
Subir imagen con express-fileupload en angular y nodejs
index.html
<html>
<body>
<form ref='uploadForm'
id='uploadForm'
action='http://localhost:8080/upload'
method='post'
encType="multipart/form-data">
<input id="nombre" name="nombre" size=20 >
<input type="file" name="sampleFile" />
<input type='submit' value='Upload!' />
</form>
</body>
</html>
app.js
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
// default options
app.use(fileUpload());
app.post('/upload', function(req, res) {
console.log(req.body.nombre);
if (!req.files)
return res.status(400).send('No files were uploaded.');
let sampleFile = req.files.sampleFile;
sampleFile.mv('/temp/filename.jpg', function(err) {
if (err)
return res.status(500).send(err);
res.send('File uploaded!');
});
});
app.listen(8080, function() {
console.log("Node server running on http://localhost:8080");
});
<html>
<body>
<form ref='uploadForm'
id='uploadForm'
action='http://localhost:8080/upload'
method='post'
encType="multipart/form-data">
<input id="nombre" name="nombre" size=20 >
<input type="file" name="sampleFile" />
<input type='submit' value='Upload!' />
</form>
</body>
</html>
app.js
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
// default options
app.use(fileUpload());
app.post('/upload', function(req, res) {
console.log(req.body.nombre);
if (!req.files)
return res.status(400).send('No files were uploaded.');
let sampleFile = req.files.sampleFile;
sampleFile.mv('/temp/filename.jpg', function(err) {
if (err)
return res.status(500).send(err);
res.send('File uploaded!');
});
});
app.listen(8080, function() {
console.log("Node server running on http://localhost:8080");
});
Instalacion de Crystal Reports en Visual Studio 2017
http://www.crystalreports.com/crystal-reports-visual-studio/
Entrar a este link, registrarse, y hacer click en "Installation package for visual studio ide"
Esto baja el paquete: CRforVS_13_0_22.exe
**** IMPORTANTE EJECUTARLO COMO ADMINISTRADOR Y CON TODOS LOS VISUAL STUDIO CERRADOS ****
**** DEJAR MARCADO 64bit RUNTIME ****
fuente: https://wiki.scn.sap.com/wiki/display/BOBJ/Crystal+Reports%2C+Developer+for+Visual+Studio+Downloads
Entrar a este link, registrarse, y hacer click en "Installation package for visual studio ide"
Esto baja el paquete: CRforVS_13_0_22.exe
**** IMPORTANTE EJECUTARLO COMO ADMINISTRADOR Y CON TODOS LOS VISUAL STUDIO CERRADOS ****
**** DEJAR MARCADO 64bit RUNTIME ****
fuente: https://wiki.scn.sap.com/wiki/display/BOBJ/Crystal+Reports%2C+Developer+for+Visual+Studio+Downloads
Authorization en WebApi con ActionFilterAttribute
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Servicios
{
public class FiltroAuthorization : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// pre-processing
Debug.WriteLine("ACTION 1 DEBUG pre-processing logging");
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
}
Debug.WriteLine("ACTION 1 DEBUG OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString());
}
}
}
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Servicios
{
public class FiltroAuthorization : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// pre-processing
Debug.WriteLine("ACTION 1 DEBUG pre-processing logging");
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
}
Debug.WriteLine("ACTION 1 DEBUG OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString());
}
}
}
En WebApiConfig.cs
config.Filters.Add(new FiltroAuthorization());
Layout de dos columnas con encabezado y pie con div y css
estilos.css
*** en el caso en que se utilice en Angular, el body no ponerlo (iria en el index.html) ***
body {
padding: 0; margin: 0;
}
.encabezado
{
float: top;
width: 100%;
height: 14%;
}
.titulo
{
background-color: lightgray;
padding: 10px;
height: 100%
}
.principal
{
background-color: magenta;
width: 100%;
height: 86%;
}
.navegacion
{
float: left;
background-color: yellow;
width: 15%;
height: 92%;
overflow-y: auto;
}
.contenido
{
float: left;
background-color: orange;
width: 85%;
height: 92%;
overflow-y: auto;
}
.pie
{
background-color: red;
color: yellow;
font-weight: bold;
width: 100%;
height: 100%;
}
.seccion
{
padding: 10px;
}
.mensajes
{
background-color: pink;
color: blue;
height: 100%;
}
.menu
{
padding: 1px;
}
index.html
<div id="contenedor" style="height: 100vh">
<div class="encabezado">
<div class="titulo">
<div align="right">
Encabezado
</div>
</div>
</div>
<div class="principal">
<div class="navegacion">
<div class="menu">
Menu
</div>
</div>
<div class="contenido">
<div class="seccion">
Contenido
</div>
</div>
<div class="pie">
<div class="mensajes">
Mensajes
</div>
</div>
</div>
</div>
*** en el caso en que se utilice en Angular, el body no ponerlo (iria en el index.html) ***
body {
padding: 0; margin: 0;
}
.encabezado
{
float: top;
width: 100%;
height: 14%;
}
.titulo
{
background-color: lightgray;
padding: 10px;
height: 100%
}
.principal
{
background-color: magenta;
width: 100%;
height: 86%;
}
.navegacion
{
float: left;
background-color: yellow;
width: 15%;
height: 92%;
overflow-y: auto;
}
.contenido
{
float: left;
background-color: orange;
width: 85%;
height: 92%;
overflow-y: auto;
}
.pie
{
background-color: red;
color: yellow;
font-weight: bold;
width: 100%;
height: 100%;
}
.seccion
{
padding: 10px;
}
.mensajes
{
background-color: pink;
color: blue;
height: 100%;
}
.menu
{
padding: 1px;
}
index.html
<div id="contenedor" style="height: 100vh">
<div class="encabezado">
<div class="titulo">
<div align="right">
Encabezado
</div>
</div>
</div>
<div class="principal">
<div class="navegacion">
<div class="menu">
Menu
</div>
</div>
<div class="contenido">
<div class="seccion">
Contenido
</div>
</div>
<div class="pie">
<div class="mensajes">
Mensajes
</div>
</div>
</div>
</div>
JWT Authentication
******* IMPORTANTE!!!! El httpinterceptor se dispara solo si se utiliza la clase HttpClient para invocar al servicio, si se utiliza Http, no se dispara!!! *******
Funcionamiento:
1. El cliente se loguea
2. El servidor genera un token jwt (RS256) encriptándolo con la libreria jwt y lo devuelve en el body
3. El cliente guarda el token en el localStorage
4. En cada invocación, mediante un interceptor, el cliente agrega el token automaticamente en el header Authorization
5. El servidor valida que todo request venga con un token, verificandolo con la libreria jwt
6. Si el token es válido, procesa el request, sino rechaza la solicitud.
Generación de clave privada pública
Para encriptar el token JWT se utiliza RS256.
El token se encripta utilizando la clave privada, y se desencripta utilizando la clave publica.
La clave privada solo sirve para encriptar, y la publica solo sirve para desencriptar.
Se puede generar el par de clave privada y publica RSA mediante este link:
http://travistidwell.com/jsencrypt/demo/
Login:
1. El cliente accede a la pantalla de login, ingresa usuario y contraseña
2. El servidor valida al usuario, y si esta ok
-genera un token jwt firmandolo con la clave privada
-retorna el token encriptado
3. El cliente almacena el token utilizando localStorage
Incluir automáticamente el token en cada invocación
1. Luego que se logueo exitosamente y se guardo en el localStorage el token, se agrega un httpInterceptor para que en cada request este incluya automáticamente el token en el header Authentication.
Servidor - validar automaticamente el token
1. En el servidor, en app.use(), se verifica mediante jwt que el token recibido en el header Authorization sea válido. Esto se hace mediante jwt.verify. La verificacion se realiza utilizando la clave publica, de las dos que se generaron en el primer paso. Con esta verificacion es suficiente, porque si el token encriptado fue alterado, no sera verificado como valido, ante lo cual se cancela el request.
Servidor:
var express = require("express"), app = express(), appLogin = express(), bodyParser = require("body-parser"), methodOverride = require("method-override"), jwt = require("jsonwebtoken"), fs = require("fs") app.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization'); res.setHeader('Access-Control-Allow-Credentials', true); next(); }); app.use(function (req, res, next) { if (req.header('Access-Control-Request-Method') != undefined) return next(); else { const RSA_PUBLIC_KEY = fs.readFileSync('./public.key'); var token = req.header('Authorization'); jwt.verify(token, RSA_PUBLIC_KEY, function(err, decoded) { if (err) { console.log("No autorizado"); res.sendStatus(401); } else { console.log("Autorizado"); next(); } }); } }); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(methodOverride()); var router = express.Router(); app.use(router); //LOGIN appLogin.use(bodyParser.urlencoded({ extended: false })); appLogin.use(bodyParser.json()); appLogin.use(methodOverride()); var router2 = express.Router(); appLogin.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization'); res.setHeader('Access-Control-Allow-Credentials', true); next(); }); appLogin.use(router2); router2.post('/login', validarLogin); router.get('/prueba', function(req, res) { var p = [{nombre: 'carlos', apellido: 'russo'}, {nombre: 'karina', apellido: 'ortiz'}]; res.send(p); }); function validarLogin(req,res) { var message; if (req.body.usuario != "crusso") { message="Usuario no existe"; } else { if (req.body.password != "abc123") { message="Password incorrecto"; } else{ message="ok"; } } if (message != "ok") res.send(JSON.stringify(message)); else { const RSA_PRIVATE_KEY = fs.readFileSync('./private.key'); const token = jwt.sign({}, RSA_PRIVATE_KEY, { algorithm: 'RS256', expiresIn: 120, subject: req.body.usuario }); console.log(token); res.send(JSON.stringify({'token' : token})); } } app.listen(8080, function() { console.log("Node server running on http://localhost:8080"); }); appLogin.listen(8081, function() { console.log("Node server running on http://localhost:8081"); });
Cliente:
app.component.html
<form (ngSubmit)="onSubmit()" method="POST">
Usuario: <input type="text" [(ngModel)]="usuario" name="usuario">
<br>
Password:<input type="password" [(ngModel)]="password" name="password">
<br>
<input type="submit" value="Enviar" />
</form>
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { AuthenticationService } from './_services/authentication.service';
import { Http } from '@angular/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
usuario: string;
password: string;
ngOnInit() {
this.usuario = "crusso";
this.password = "abc123";
}
title = 'app';
constructor(private httpClient: HttpClient, private authenticationService : AuthenticationService) { }
metodo1(): void {
this.httpClient.get("http://localhost:8080/prueba").subscribe((datos) => {
console.log(datos);
});
}
onSubmit() {
console.log(this.usuario + " " + this.password);
this.authenticationService.login(this.usuario, this.password).subscribe((datos) => {
console.log(datos);
});
}
logout() {
console.log("logout");
this.authenticationService.logout();
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { InterceptorHttp } from './_interceptor/interceptorhttp'
import { AppComponent } from './app.component';
import { AuthenticationService } from './_services/authentication.service';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { RouterOutlet } from '@angular/router';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
RouterModule,
HttpModule,
HttpClientModule,
//RouterModule.forRoot([ {path: 'usuarios', component: PruebaComponent} ])
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorHttp,
multi: true,
},
AuthenticationService
],
bootstrap: [AppComponent]
})
export class AppModule { }
interceptorhttp.ts
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
@Injectable()
export class InterceptorHttp implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler):Observable<HttpEvent<any>> {
var token = '';
if (localStorage.getItem('currentUser') != null)
{
var t = JSON.parse(localStorage.getItem('currentUser'));
token = t.token;
}
else
token = '';
const customHeaderRequest = req.clone({
headers: req.headers.set('Authorization', token)
});
console.log("INTERCEPTANDO: " + token);
return next.handle(customHeaderRequest);
}
}
authentication.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map'
@Injectable()
export class AuthenticationService {
constructor(private http: Http) {
var currentUser = JSON.parse(localStorage.getItem('currentUser'));
console.log("CONSTRUCTOR: " + currentUser);
}
login(usuario: string, password: string): Observable<boolean> {
return this.http.post('http://localhost:8081/login', { usuario: usuario, password: password })
.map((response: Response) => {
let token = response.json() && response.json().token;
if (token) {
localStorage.setItem('currentUser', JSON.stringify(response.json()));
return true;
} else {
return false;
}
});
}
logout(): boolean {
localStorage.removeItem('currentUser');
return true;
}
}
Fuente: https://blog.angular-university.io/angular-jwt-authentication/
Funcionamiento:
1. El cliente se loguea
2. El servidor genera un token jwt (RS256) encriptándolo con la libreria jwt y lo devuelve en el body
3. El cliente guarda el token en el localStorage
4. En cada invocación, mediante un interceptor, el cliente agrega el token automaticamente en el header Authorization
5. El servidor valida que todo request venga con un token, verificandolo con la libreria jwt
6. Si el token es válido, procesa el request, sino rechaza la solicitud.
Generación de clave privada pública
Para encriptar el token JWT se utiliza RS256.
El token se encripta utilizando la clave privada, y se desencripta utilizando la clave publica.
La clave privada solo sirve para encriptar, y la publica solo sirve para desencriptar.
Se puede generar el par de clave privada y publica RSA mediante este link:
http://travistidwell.com/jsencrypt/demo/
1. El cliente accede a la pantalla de login, ingresa usuario y contraseña
2. El servidor valida al usuario, y si esta ok
-genera un token jwt firmandolo con la clave privada
-retorna el token encriptado
3. El cliente almacena el token utilizando localStorage
Incluir automáticamente el token en cada invocación
1. Luego que se logueo exitosamente y se guardo en el localStorage el token, se agrega un httpInterceptor para que en cada request este incluya automáticamente el token en el header Authentication.
Servidor - validar automaticamente el token
1. En el servidor, en app.use(), se verifica mediante jwt que el token recibido en el header Authorization sea válido. Esto se hace mediante jwt.verify. La verificacion se realiza utilizando la clave publica, de las dos que se generaron en el primer paso. Con esta verificacion es suficiente, porque si el token encriptado fue alterado, no sera verificado como valido, ante lo cual se cancela el request.
Servidor:
var express = require("express"), app = express(), appLogin = express(), bodyParser = require("body-parser"), methodOverride = require("method-override"), jwt = require("jsonwebtoken"), fs = require("fs") app.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization'); res.setHeader('Access-Control-Allow-Credentials', true); next(); }); app.use(function (req, res, next) { if (req.header('Access-Control-Request-Method') != undefined) return next(); else { const RSA_PUBLIC_KEY = fs.readFileSync('./public.key'); var token = req.header('Authorization'); jwt.verify(token, RSA_PUBLIC_KEY, function(err, decoded) { if (err) { console.log("No autorizado"); res.sendStatus(401); } else { console.log("Autorizado"); next(); } }); } }); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(methodOverride()); var router = express.Router(); app.use(router); //LOGIN appLogin.use(bodyParser.urlencoded({ extended: false })); appLogin.use(bodyParser.json()); appLogin.use(methodOverride()); var router2 = express.Router(); appLogin.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization'); res.setHeader('Access-Control-Allow-Credentials', true); next(); }); appLogin.use(router2); router2.post('/login', validarLogin); router.get('/prueba', function(req, res) { var p = [{nombre: 'carlos', apellido: 'russo'}, {nombre: 'karina', apellido: 'ortiz'}]; res.send(p); }); function validarLogin(req,res) { var message; if (req.body.usuario != "crusso") { message="Usuario no existe"; } else { if (req.body.password != "abc123") { message="Password incorrecto"; } else{ message="ok"; } } if (message != "ok") res.send(JSON.stringify(message)); else { const RSA_PRIVATE_KEY = fs.readFileSync('./private.key'); const token = jwt.sign({}, RSA_PRIVATE_KEY, { algorithm: 'RS256', expiresIn: 120, subject: req.body.usuario }); console.log(token); res.send(JSON.stringify({'token' : token})); } } app.listen(8080, function() { console.log("Node server running on http://localhost:8080"); }); appLogin.listen(8081, function() { console.log("Node server running on http://localhost:8081"); });
Cliente:
app.component.html
<form (ngSubmit)="onSubmit()" method="POST">
Usuario: <input type="text" [(ngModel)]="usuario" name="usuario">
<br>
Password:<input type="password" [(ngModel)]="password" name="password">
<br>
<input type="submit" value="Enviar" />
</form>
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { AuthenticationService } from './_services/authentication.service';
import { Http } from '@angular/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
usuario: string;
password: string;
ngOnInit() {
this.usuario = "crusso";
this.password = "abc123";
}
title = 'app';
constructor(private httpClient: HttpClient, private authenticationService : AuthenticationService) { }
metodo1(): void {
this.httpClient.get("http://localhost:8080/prueba").subscribe((datos) => {
console.log(datos);
});
}
onSubmit() {
console.log(this.usuario + " " + this.password);
this.authenticationService.login(this.usuario, this.password).subscribe((datos) => {
console.log(datos);
});
}
logout() {
console.log("logout");
this.authenticationService.logout();
}
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { InterceptorHttp } from './_interceptor/interceptorhttp'
import { AppComponent } from './app.component';
import { AuthenticationService } from './_services/authentication.service';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { RouterOutlet } from '@angular/router';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
RouterModule,
HttpModule,
HttpClientModule,
//RouterModule.forRoot([ {path: 'usuarios', component: PruebaComponent} ])
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorHttp,
multi: true,
},
AuthenticationService
],
bootstrap: [AppComponent]
})
export class AppModule { }
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
@Injectable()
export class InterceptorHttp implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler):Observable<HttpEvent<any>> {
var token = '';
if (localStorage.getItem('currentUser') != null)
{
var t = JSON.parse(localStorage.getItem('currentUser'));
token = t.token;
}
else
token = '';
const customHeaderRequest = req.clone({
headers: req.headers.set('Authorization', token)
});
console.log("INTERCEPTANDO: " + token);
return next.handle(customHeaderRequest);
}
}
authentication.service.ts
import { Injectable } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map'
@Injectable()
export class AuthenticationService {
constructor(private http: Http) {
var currentUser = JSON.parse(localStorage.getItem('currentUser'));
console.log("CONSTRUCTOR: " + currentUser);
}
login(usuario: string, password: string): Observable<boolean> {
return this.http.post('http://localhost:8081/login', { usuario: usuario, password: password })
.map((response: Response) => {
let token = response.json() && response.json().token;
if (token) {
localStorage.setItem('currentUser', JSON.stringify(response.json()));
return true;
} else {
return false;
}
});
}
logout(): boolean {
localStorage.removeItem('currentUser');
return true;
}
}
Fuente: https://blog.angular-university.io/angular-jwt-authentication/
IIS ASP.NET AutoStart
La primera vez que un usuario accede a una aplicacion, esta es compilada, lo cual produce una demora.
Para evitarlo, se puede configurar el modo AutoStart en IIS
En el application pool:
click derecho / configuracion avanzada:
start mode: always running
En el sitio web:
click derecho / administrar aplicacion / configuracion avanzada:
preload enabled: true
Para evitarlo, se puede configurar el modo AutoStart en IIS
En el application pool:
click derecho / configuracion avanzada:
start mode: always running
En el sitio web:
click derecho / administrar aplicacion / configuracion avanzada:
preload enabled: true
Authorization token ANGULAR NODEJS con Interceptor http
******* IMPORTANTE!!!! El httpinterceptor se dispara solo si se utiliza la clase HttpClient para invocar al servicio, si se utiliza Http, no se dispara!!! *******
Servidor
app.js
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
methodOverride = require("method-override");
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
if (req.header('Authorization') == undefined)
return next();
if (req.header('Authorization') == "Bearer #112222")
{
console.log("Autorizado");
next();
} else
{
console.log("NO autorizado");
res.sendStatus(401);
}
});
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
var router = express.Router();
app.use(router);
router.get('/prueba', function(req, res) {
var p = [{nombre: 'carlos', apellido: 'russo'},
{nombre: 'karina', apellido: 'ortiz'}];
res.send(p);
});
app.listen(8080, function() {
console.log("Node server running on http://localhost:8080");
});
Cliente
app.component.html
<div style="text-align:center">
<h1>Prueba de authentication con token</h1>
<button (click)="metodo1()">Method 1</button>
</div>
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from "@angular/common/http";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
constructor(private httpClient: HttpClient) { }
metodo1(): void {
this.httpClient.get("http://localhost:8080/prueba").subscribe(
success => {
console.log("Ok!");
console.log(success);
}
);
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { InterceptorHttp } from './interceptorhttp'
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorHttp,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
interceptorhttp.ts
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
//import {Http, Headers, RequestOptions } from '@angular/http';
@Injectable()
export class InterceptorHttp implements HttpInterceptor {
constructor() {
}
intercept(req: HttpRequest<any>,
next: HttpHandler):Observable<HttpEvent<any>> {
console.log("interceptando!!!");
const customHeaderRequest = req.clone({
headers: req.headers.set('Authorization', 'Bearer #112222')
});
console.log(req);
return next.handle(customHeaderRequest);
}
}
Servidor
app.js
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
methodOverride = require("method-override");
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type, x-access-token, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
if (req.header('Authorization') == undefined)
return next();
if (req.header('Authorization') == "Bearer #112222")
{
console.log("Autorizado");
next();
} else
{
console.log("NO autorizado");
res.sendStatus(401);
}
});
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
var router = express.Router();
app.use(router);
router.get('/prueba', function(req, res) {
var p = [{nombre: 'carlos', apellido: 'russo'},
{nombre: 'karina', apellido: 'ortiz'}];
res.send(p);
});
app.listen(8080, function() {
console.log("Node server running on http://localhost:8080");
});
Cliente
app.component.html
<div style="text-align:center">
<h1>Prueba de authentication con token</h1>
<button (click)="metodo1()">Method 1</button>
</div>
app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from "@angular/common/http";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
constructor(private httpClient: HttpClient) { }
metodo1(): void {
this.httpClient.get("http://localhost:8080/prueba").subscribe(
success => {
console.log("Ok!");
console.log(success);
}
);
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { InterceptorHttp } from './interceptorhttp'
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: InterceptorHttp,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
interceptorhttp.ts
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
//import {Http, Headers, RequestOptions } from '@angular/http';
@Injectable()
export class InterceptorHttp implements HttpInterceptor {
constructor() {
}
intercept(req: HttpRequest<any>,
next: HttpHandler):Observable<HttpEvent<any>> {
console.log("interceptando!!!");
const customHeaderRequest = req.clone({
headers: req.headers.set('Authorization', 'Bearer #112222')
});
console.log(req);
return next.handle(customHeaderRequest);
}
}
Angular - Failed to load xxxxx: Response for preflight has invalid HTTP status code 404
Si es un llamado POST, verificar que la url no tenga los parametros tipo GET
ej
en lugar de: router.post('http://localhost:8080/competidores/guardar/:competidor', function(req, res)
debe ser: router.post('http://localhost:8080/competidores/guardar', function(req, res)
y los parametros se obtienen con req.body
ej
en lugar de: router.post('http://localhost:8080/competidores/guardar/:competidor', function(req, res)
debe ser: router.post('http://localhost:8080/competidores/guardar', function(req, res)
y los parametros se obtienen con req.body
Suscribirse a:
Entradas (Atom)