ng new angular-meanstack-authentication
转到Angular用户身份验证项目文件夹
cd angular-meanstack-authentication
创建以下组件
ng g c components/signin
ng g c components/signup
ng g c components/user-profile
安装Bootstrap 4
npm install bootstrap
在angular.json文件中添加Bootstrap 4样式表路径
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
]
启动Angular应用
ng serve --open
git clone https://github.com/SinghDigamber/node-token-based-authentication.git
进入服务器文件夹
cd node-token-based-authentication
运行`npm install`以安装所需的软件包
打开其他终端运行 `mongod`
安装nodemon软件包
当服务器文件中发生任何更改时,它有助于启动节点服务器。
npm install nodemon --save-dev
打开终端运行 `nodemon`
API Methods API URL
GET (Users List) /api
POST (Sign in) /api/signin
POST (Sign up) /api/register-user
GET (User Profile) /api/user-profile/id
PUT (Update User) /api/update-user/id
DELETE (Delete User) /api/delete-user/id
HttpClientModule在app.module.ts文件中导入服务。
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule
]
})
在共享文件夹内创建shared/user.ts文件,并在其中包含以下代码。
export class User {
id: string;
name: string;
email: string;
password: string;
}
接下来,运行以下命令以创建用户身份验证服务。
ng g s shared/auth
将以下代码添加到shared / auth.service.ts文件中。
import {Injectable} from '@angular/core';
import {User} from './user';
import {Observable, throwError} from 'rxjs';
import {catchError, map} from 'rxjs/operators';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import {Router} from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService {
endpoint = 'http://localhost:4000/api';
headers = new HttpHeaders().set('Content-Type', 'application/json');
currentUser = {};
constructor(
private http: HttpClient,
public router: Router
) {
}
// Sign-up
signUp(user: User): Observable {
const api = `${this.endpoint}/register-user`;
return this.http.post(api, user)
.pipe(
catchError(this.handleError)
);
}
// Sign-in
signIn(user: User) {
return this.http.post(`${this.endpoint}/signin`, user)
.subscribe((res: any) => {
localStorage.setItem('access_token', res.token);
this.getUserProfile(res._id).subscribe((res) => {
this.currentUser = res;
this.router.navigate(['user-profile/' + res.msg._id]);
});
});
}
getToken() {
return localStorage.getItem('access_token');
}
get isLoggedIn(): boolean {
const authToken = localStorage.getItem('access_token');
return (authToken !== null) ? true : false;
}
doLogout() {
const removeToken = localStorage.removeItem('access_token');
if (removeToken == null) {
this.router.navigate(['log-in']);
}
}
// User profile
getUserProfile(id): Observable {
const api = `${this.endpoint}/user-profile/${id}`;
return this.http.get(api, {headers: this.headers}).pipe(
map((res: Response) => {
return res || {};
}),
catchError(this.handleError)
);
}
// Error
handleError(error: HttpErrorResponse) {
let msg = '';
if (error.error instanceof ErrorEvent) {
// client-side error
msg = error.error.message;
} else {
// server-side error
msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(msg);
}
}
signUp()将存储的MongoDB数据库的用户名,电子邮件地址和密码。
通过使用bcryptjs,我们将密码安全地存储在数据库中。
signIn()方法允许使用JSON网络令牌由节点服务器生成的用户在应用程序的访问。
我们从API响应中获取JWT令牌并存储在本地存储中,然后在getToken方法中,我们通过本地存储getItem方法访问该令牌。
该isLoggedIn如果用户在其他人返回false记录方法返回true。
在共享文件夹中创建authconfig.interceptor.ts文件
import {Injectable} from '@angular/core';
import {HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {AuthService} from './auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {
}
intercept(req: HttpRequest, next: HttpHandler) {
// 获取JWT令牌
const authToken = this.authService.getToken();
// 设置Authorization标头
req = req.clone({
setHeaders: {
Authorization: 'Bearer ' + authToken
}
});
return next.handle(req);
}
}
在app.module.ts文件中导入HTTP_INTERCEPTORS并在数组中设置
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}],
运行以下命令来设置CanActivate接口类,它会阻止访问者访问应用程序中的某些URL。我们只希望登录用户访问/user-profile
ng g guard shared/auth
auth.guard.ts文件中添加以下代码
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {AuthService} from './../shared/auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
public authService: AuthService,
public router: Router
) {
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable | Promise | boolean {
if (this.authService.isLoggedIn !== true) {
window.alert('Access not allowed!');
this.router.navigate(['log-in']);
}
return true;
}
}
app-routing.module.ts文件导入AuthGuard接口类
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {SigninComponent} from './components/signin/signin.component';
import {SignupComponent} from './components/signup/signup.component';
import {UserProfileComponent} from './components/user-profile/user-profile.component';
import {AuthGuard} from './shared/auth.guard';
const routes: Routes = [
{path: '', redirectTo: '/log-in', pathMatch: 'full'},
{path: 'log-in', component: SigninComponent},
{path: 'sign-up', component: SignupComponent},
{path: 'user-profile/:id', component: UserProfileComponent, canActivate: [AuthGuard]}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
By Digamber Rawat Last updated on November 9, 2019
FacebookTwitterMore3
Welcome, fellas! Today, In this step-by-step Angular 8|9 tutorial, we are going to understand how to build a secure user authentication system using JSON web tokens (JWT) and RESTful Auth APIs built with express, node and mongoDB.
We will be using the token-based user authentication RESTful APIs which we covered in our earlier tutorial. Learn how to build secure (JWT) Token-Based RESTful authentication API with Node/Express Js? from scratch.
JWT refers to JSON Web token. It’s a token in string form validated and generated by a web server. This string-based token helps in communicating between the client and the server.
Let’s understand how does the JWT help in transferring the data securely between the client and the server.
User information is sent to the client like username and password using an HTTP POST request to the webserver. Web server identifies the user information and creates a token and send it back to the client. Client store that token into local storage or a session and also set it to the header. On the next HTTP call, that token is verified by the server, and web server returns the response to the client.
Click below to get the full code of this tutorial on GitHub.
Git Repo
Table of contents
Let’s get started by installing the basic Angular app, enter the following command in your terminal:
ng new angular-meanstack-authentication
# ? Would you like to add Angular routing? Yes
# ? Which stylesheet format would you like to use? CSS
Next, head over to the Angular user authentication project folder:
cd angular-meanstack-authentication
To make things simpler create a separate front-end and backend (server) in Angular app. Our Angular 8/9 user auth app will have signin, signup and user-profile pages.
Create specific components folder in src/app/components in Angular app and create the following components in it.
ng g c components/signin
ng g c components/signup
ng g c components/user-profile
Next, install Bootstrap 4.
npm install bootstrap
Add the Bootstrap 4 stylesheet path in angular.json file.
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
]
Start your Angular app.
ng serve --open
Run the following command to clone Node.js token-based auth REST API from GitHub in your Angular’s root folder.
git clone https://github.com/SinghDigamber/node-token-based-authentication.git
Get inside the server folder:
cd node-token-based-authentication
Next, install npm packages to set up and start the Node server:
Run `npm install`
to install required packages
Open other terminal run `mongod`
Next, install the nodemon NPM package for development purpose with --save-dev
attribute, it helps in starting the node server when any change occurs in the server files.
npm install nodemon --save-dev
Open terminal run `nodemon`
Following auth APIs we are going to use in this tutorial.
API Methods | API URL |
---|---|
GET (Users List) | /api |
POST (Sign in) | /api/signin |
POST (Sign up) | /api/register-user |
GET (User Profile) | /api/user-profile/id |
PUT (Update User) | /api/update-user/id |
DELETE (Delete User) | /api/delete-user/id |
Open API URL on http://localhost:4000/api
To handle REST APIs via HTTP requests in our Angular user authentication app. We need to import Angular HttpClient service in the auth module.
Import HttpClientModule
service in app.module.ts
file.
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule
]
})
Now create Angular auth service and user class, these files will handle all the JWT user authentication related APIs in our project.
Inside the shared folder create shared/user.ts
file and include the following code inside of it.
export class User {
_id: String;
name: String;
email: String;
password: String;
}
Next, run below command to create user auth service.
ng g s shared/auth
Add the following code in the shared/auth.service.ts file.
import { Injectable } from '@angular/core';
import { User } from './user';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService {
endpoint: string = 'http://localhost:4000/api';
headers = new HttpHeaders().set('Content-Type', 'application/json');
currentUser = {};
constructor(
private http: HttpClient,
public router: Router
) {
}
// Sign-up
signUp(user: User): Observable {
let api = `${this.endpoint}/register-user`;
return this.http.post(api, user)
.pipe(
catchError(this.handleError)
)
}
// Sign-in
signIn(user: User) {
return this.http.post(`${this.endpoint}/signin`, user)
.subscribe((res: any) => {
localStorage.setItem('access_token', res.token)
this.getUserProfile(res._id).subscribe((res) => {
this.currentUser = res;
this.router.navigate(['user-profile/' + res.msg._id]);
})
})
}
getToken() {
return localStorage.getItem('access_token');
}
get isLoggedIn(): boolean {
let authToken = localStorage.getItem('access_token');
return (authToken !== null) ? true : false;
}
doLogout() {
let removeToken = localStorage.removeItem('access_token');
if (removeToken == null) {
this.router.navigate(['log-in']);
}
}
// User profile
getUserProfile(id): Observable {
let api = `${this.endpoint}/user-profile/${id}`;
return this.http.get(api, { headers: this.headers }).pipe(
map((res: Response) => {
return res || {}
}),
catchError(this.handleError)
)
}
// Error
handleError(error: HttpErrorResponse) {
let msg = '';
if (error.error instanceof ErrorEvent) {
// client-side error
msg = error.error.message;
} else {
// server-side error
msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(msg);
}
}
In this part of the tutorial, we are going to set the JSON web token in the header using Angular 8/9 HttpInterceptor. To set the authorization header, first create the authconfig.interceptor.ts file in the shared folder.
import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler } from "@angular/common/http";
import { AuthService } from "./auth.service";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) { }
intercept(req: HttpRequest, next: HttpHandler) {
const authToken = this.authService.getToken();
req = req.clone({
setHeaders: {
Authorization: "Bearer " + authToken
}
});
return next.handle(req);
}
}
Import the AuthService in and inject inside the constructor. In the intercept(){…} method call the getToken() method to get the JWT token then within the req.clone method set the Authorization header and call teh next.handle() method.
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './shared/authconfig.interceptor';
@NgModule({
declarations: [...],
imports: [HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
],
bootstrap: [...]
})
export class AppModule { }
Next, import the HTTP_INTERCEPTORS in the app.module.ts file and set the HTTP_INTERCEPTORS along with AuthInterceptor in providers:[...]
array.
Run following command to set up CanActivate interface class, It stops visitors to access certain urls in the Angular app. In our case we only want logged-in users to access the /user-profile
URL.
ng g guard shared/auth
Next, add the following code in the auth.guard.ts file.
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot,
UrlTree, CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './../shared/auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
public authService: AuthService,
public router: Router
) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable | Promise | boolean {
if (this.authService.isLoggedIn !== true) {
window.alert("Access not allowed!");
this.router.navigate(['log-in'])
}
return true;
}
}
Then, go to app-routing.module.ts file and import the AuthGuard interface class and inject the AuthGuard in the route as given below.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SigninComponent } from './components/signin/signin.component';
import { SignupComponent } from './components/signup/signup.component';
import { UserProfileComponent } from './components/user-profile/user-profile.component';
import { AuthGuard } from "./shared/auth.guard";
const routes: Routes = [
{ path: '', redirectTo: '/log-in', pathMatch: 'full' },
{ path: 'log-in', component: SigninComponent },
{ path: 'sign-up', component: SignupComponent },
{ path: 'user-profile/:id', component: UserProfileComponent, canActivate: [AuthGuard] }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Import ReactiveFormsModule
and FormsModule
in app.module.ts
imports: [
ReactiveFormsModule,
FormsModule,
BrowserModule,
AppRoutingModule,
HttpClientModule,
],
components/signup.component.ts file add the following code
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';
import {AuthService} from './../../shared/auth.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.css']
})
export class SignupComponent implements OnInit {
signupForm: FormGroup;
constructor(
public fb: FormBuilder,
public authService: AuthService,
public router: Router
) {
this.signupForm = this.fb.group({
name: [''],
email: [''],
mobile: [''],
password: ['']
});
}
ngOnInit() {
}
registerUser() {
this.authService.signUp(this.signupForm.value).subscribe((res) => {
if (res.result) {
console.log(res);
this.signupForm.reset();
this.router.navigate(['log-in']);
}
});
}
}
components/signup.component.html
components/signin.component.ts
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';
import {AuthService} from './../../shared/auth.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-signin',
templateUrl: './signin.component.html',
styleUrls: ['./signin.component.css']
})
export class SigninComponent implements OnInit {
signinForm: FormGroup;
constructor(
public fb: FormBuilder,
public authService: AuthService,
public router: Router
) {
this.signinForm = this.fb.group({
email: [''],
password: ['']
});
}
ngOnInit() {
}
loginUser() {
this.authService.signIn(this.signinForm.value);
}
}
components/signin.component.html
server / /middlewares/auth.js文件中,jwt.verify()
方法检查API请求,发现无效的令牌或JWT机密,则不呈现用户数据
components / user-profile.component.ts
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {AuthService} from './../../shared/auth.service';
import {User} from '../../shared/user';
@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.css']
})
export class UserProfileComponent implements OnInit {
currentUser: User;
constructor(
public authService: AuthService,
private actRoute: ActivatedRoute
) {
const id = this.actRoute.snapshot.paramMap.get('id');
this.authService.getUserProfile(id).subscribe(res => {
this.currentUser = res.msg;
});
}
ngOnInit() {
}
}
components / user-profile.component.html
User Profile
Name: {{this.currentUser.name}}
Email: {{this.currentUser.email}}
app / app.component.ts
import {Component} from '@angular/core';
import {AuthService} from './shared/auth.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(public authService: AuthService) {
}
logout() {
this.authService.doLogout();
}
}
app / app.component.html
Angular Mean Auth
Sign up