Angular 11-使用PHP的JWT身份验证示例和教程

2023-06-01 angular

Angular 11 - JWT Authentication Example & Tutorial With PHP

通常,通过输入用户名,电子邮件地址和/或密码来对用户进行身份验证,然后授予其访问各种资源或服务的权限。身份验证本身就依赖于维护用户的状态。这似乎违背了HTTP作为无状态协议的基本属性。


您的Angular应用程序将与生成令牌的后端进行通信。然后,Angular应用程序可以将令牌作为“授权”标头发送到后端,以显示它们已通过身份验证。 JWT应由后端检查,并应根据其有效性授予访问权限。


本教程将逐步指导您在Angular 11应用程序中开发和实现基于JWT的身份验证的过程。本教程通过使用PHP开发后端服务使您更进一步。


执行

在这一部分中,我将向您展示如何将PHP与Angular 11客户端结合使用以实现JWT身份验证。即使原理很明确,实现也必须熟悉安全最佳实践。

此处提供的示例是不完整的,并且缺少生产服务器将具有的若干功能。因此,我不建议在本教程中将源代码用于生产目的。

我假设您熟悉MySQL,Angular和PHP。您还应该在开发环境中安装composer。


步骤1:数据库准备


如果您具有所有先决条件,那么让我们开始构建一个MySQL数据库。我们将使用服务器随附的MySQL客户端。


打开终端并键入以下命令以启动客户端:


$ mysql -u root -p

根据您的MySQL配置,在出现提示时输入密码。




在显示的窗口上,运行以下命令来创建数据库。


mysql> create database jwt-database;

在我们之前创建的jwt-database中,创建一个表jwt-users,如下所示:


mysql> use jwt-database;

mysql> create table `jwt-users` (

  `user_id` int auto_increment primary key,

  `fullname` varchar(40) ,

  `username` varchar(40) ,

  `email_address` varchar(40) unique,

  `password` varchar(40) not null,

  


现在,通过运行以下命令,将cd放入我们先前创建的目录中:


    cd jwt-server

注意:根据您的开发环境,此路径可能会有所不同。


连接到数据库

在您的工作目录中,在tokens-api目录中创建一个文件夹db_configurations。

cd tokens-api && mkdir configurations

然后,

cd configurations


conn = null;

        try

        {

            $this->connection = new PDO("mysql:host=" . $this->db_host . ";dbname=" . $this->db_name, $this->db_user, $this->db_password);

            $conn->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

        }

        catch(PDOException $e){

            echo "Error " . $e->getMessage();

        }

        return $this->connect;

    }

}



步骤2:安装PHP令牌生成器软件包

PHP具有JWT库,该库可用于生成身份验证令牌,以标识访问后端服务的客户端。

要在系统中安装此PHP库,您需要安装一个作曲家。

您可以通过运行以下命令来验证其安装:

composer -v

现在,通过运行以下命令继续并导入库:

$ composer require firebase/php-jwt


为了允许我们的PHP后端和angular应用程序之间进行通信,我们需要设置CORS标头。


让我们继续创建文件header.php,并添加以下CORS脚本:


header("Access-Control-Max-Age: 3600");

header("Access-Control-Allow-Methods: POST, PUT, DELETE, UPDATE");

header("Access-Control-Allow-Origin: * ");

header("Content-Type: application/json; charset=UTF-8");

header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");



步骤3:用户注册API端点


现在我们的系统中已经有了php-jwt库,让我们继续创建一个简单的注册系统。在当前目录中,添加以下代码行。


db_connect();

$api_data = json_decode(file_get_contents("php://input"));

$full_name = $api_data->full_name;

$email_address = $api_data->email;

$password = $api_data->password;

$query = "INSERT INTO " jwt_users . "

                SET full_name = :fname,

                    email = :emailAdress,

                    password = :pwd";

$stmt = $conn->prepare($query);

$stmt->bindParam(':fname',$full_name)

$stmt->bindParam(':email', $email_address);

$stmt->bindParam(':password', $password1);

$stmt->execute();

?>



用户登录API端点


在tokens-api目录中,创建一个signin.php文件,并添加以下代码以检查客户端资格以访问我们的后端服务。


要验证用户凭据并将JSON Web令牌返回给客户端,请使用以下代码在tokens-api目录中构建一个signin.php文件脚本:


db_connect();

$api_data = json_decode(file_get_contents("php://input"));

$user_email = $api_data->email_address;

$password = $api_data->password;

$table = 'Users';

$sql = "SELECT user_id,first_name, last_name,`password` FROM " . $table . " WHERE email_address =:email  LIMIT 0,1";

$stmt = $conn->prepare( $query );

$stmt->bindParam(':email', $email_address);

$stmt->execute();

$numOfRows = $stmt->rowCount();

if($numOfRows) > 0){

    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    $user_id    = $row['id'];

    $first_name = $row['first_name'];

    $last_name = $row['last_name'];

    $pass       = $row['password'];

    if(password_verify($password, $pass))

    {

        $secret_key = "MillerJumaWilliam";

        $issuer_claim = "localhost"; 

        $audience_claim = "THE_AUDIENCE";

        $issuedat_claim = time(); // time issued 

        $notbefore_claim = $issuedat_claim + 10; 

        $expire_claim = $issuedat_claim + 60; 

        $token = array(

            "iss" => $issuer_claim,

            "aud" => $audience_claim,

            "iat" => $issuedat_claim,

            "nbf" => $notbefore_claim,

            "exp" => $expire_claim,

            "data" => array(

                "id" => $id,

                "firstName" => $first_name,

                "lastName" => $last_name,

                "userEmail" => $email_address

        ));

        $jwtValue = JWT::encode($token, $secret_key);

        echo json_encode(

            array(

                "message" => "success",

                "token" => $jwtValue,

                "email_address" => $email_address,

                "expiry" => $expire_claim

            ));

    }

    else{

        echo json_encode(array("success" => "false"));

    }

}

?>

您可以根据需要描述令牌的数据结构,但是应正确指定某些保留的JWT语句,因为它们会影响令牌的有效性。




JWT :: encode()方法将PHP数组转换为JSON格式,对有效负载进行签名,然后对最终令牌进行编码,然后再将其发送到客户端(即浏览器)。


为了注册和登录用户,我们现在有两个RESTful端点。让我们通过在'token-apifolder中运行以下命令来测试我们的端点是否正常工作。


'token-apifolder. 

bash

cd tokens-api && php -S 127.0.0.1:8000 // to start our development server

`

现在,我们已经有了带有JWT令牌的功能齐全的REST API,让我们继续创建角度项目。




设置角度项目以使用PHP身份验证端点


值得注意的是,本教程不会教您如何设置角度项目,有关更多信息,请访问角度文档。


在新的角度项目中,运行以下命令以创建authService服务:


bash

$ ng generate service auth

我们将使用该服务来登录和注销用户。让我们将以下代码添加到我们的身份验证服务中。


ts


import { Injectable } from '@angular/core';

import { HttpClient } from '@angular/common/http';

import { BehaviorSubject, Observable } from 'rxjs';

import { map } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })

export class AuthService {

public baseUrl = "localhost:8000";

private loggedUserSubject: BehaviorSubject;

public loggedInUser: Observable;

constructor(private httpClient: HttpClient) {

getLoggedUser = JSON.parse(localStorage.getItem('loggedInUser'));

this.loggedUserSubject = new BehaviorSubject(this.getLoggedUser));

this.loggedInUser = this.loggedUserSubject.asObservable();

}

loginUser(emailAddress: string, password: string) {

return this.http.post(${baseUrl}/, { emailAddress, password })

.pipe(map(response=> {

localStorage.setItem('loggedInUser', JSON.stringify(response));

this.loggedUserSubject.next(response);

console.log(response);

return response;

}));

}

logoutUser() {

localStorage.removeItem('loggedInUser');

this.loggedUserSubject.next(null);

}

public get loggedInUserValue(){

return this.loggedUserSubject.value;

}

}

在上面的auth服务中,当用户登录和退出系统时,RxJS主题和可观察对象用于存储当前用户。


设置登录组件


现在,我们已经有了将HTTP请求发送到PHP端点的服务,让我们继续运行下面的命令,创建一个登录组件来测试我们的代码:


bash

$ ng g c login



在新的组件模板中,复制并粘贴以下代码:

html

Authentication Form

Email Address

                               

                        

我们上面创建的表单使用了Angular的Reactive Forms模块。触发点击事件后,用户信息就会发送到我们的组件。


准备好我们的登录模板后,在yourlogin.compnent.ts文件中,添加以下代码段以获取用户输入。


正是在此脚本中,捕获了用户的值,然后将其发送到我们之前通过auth服务创建的API服务。


ts


import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { AuthService } from './service/auth.service';
@Component({ 
templateUrl: 'login.component.html' 
})
export class LoginComponent implements OnInit {
signinForm: FormGroup;
constructor(
    private fb: FormBuilder,
    private authService: AuthService
) {  }
ngOnInit() {
    this.signinForm = this.fb.group({
        email: [null, [Validators.required, Validators.email]],
        password: [null, Validators.required]
    });
}
get form() 
{ 
    return this.signinForm.controls; 
}
onSubmit() {
    this.authService.loginUser(this.form.email.value, this.form.password.value)
        .subscribe(
            data => {
                console.log(data);
            },
            error => {
                console.log(error);
            });
}



将登录令牌存储在本地存储中

Angular附带了HTTP拦截器。因此,任何请求都将传递一个令牌,该令牌将在我们的后端用于验证用户的有效性。

让我们继续运行以下命令,为我们的应用程序AuthInterceptor创建一个拦截器:


bash 

$ ng g interceptor auth

ts


...

import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';

import { Observable } from 'rxjs';

import { AuthService } from './service/auth.module';

@Injectable()

export class AuthInterceptor implements HttpInterceptor {

constructor(private authService: AuthService) { }

intercept(request: HttpRequest, next: HttpHandler): Observable<HttpEvent> {

let loggedInUser = this.authService.currentUserValue;

token = JSON.parse(localStorage.getItem(user.token));

if (token) {

request = request.clone({

setHeaders: {

Authorization:Bearer ${token}

}

});

}

return next.handle(request);

}

}

现在,让我们继续将此脚本添加到我们的app.module.ts中,以确保克隆我们发送的所有请求并附加令牌。


ts


import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { ReactiveFormsModule } from '@angular/forms';

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

import { AppComponent } from './app.component';

import { appRoutingModule } from './app.routing';

import { AuthInterceptor} from 'helpers/AuthInterceptor';

import { DashboardComponent } from './dashboard';

import { LoginComponent } from './login';

@NgModule({

imports: [

BrowserModule,

ReactiveFormsModule,

HttpClientModule,

appRoutingModule

],

declarations: [

AppComponent,

DashboardComponent,

LoginComponent

],

providers: [

{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true 

],

bootstrap: [AppComponent]

})

export class AppModule { }



好吧,让我们通过运行以下命令来启动我们的角度应用程序:


bash

ng serve --open //starts on port 4200 by default unless you specify otherwise

现在,当生成的令牌存储在浏览器的本地存储中时,您可以向我们的PHP终结点发出请求并登录。



结论

在本教程中,我们学习了如何在具有PHP RESTful API的Angular 11应用程序中使用JWT身份验证。我们还在Angular应用程序中实现了其他身份验证策略,例如令牌身份验证。


快乐的编码。



转:https://dev.to/jumamiller/angular-11-jwt-authentication-example-tutorial-with-php-2d7d



相关文章