首页 > 解决方案 > 如何将受 Jwt 保护的 Express.js Rest api 与 Angular 应用程序连接起来

问题描述

我用 json web token 保护了我的 api。如何将其连接到我的 Angular 应用程序。应用程序中将没有登录和注册。

我对 Google、youtube 和 stackoverflow 做了很多研究。但我从来没有找到我想要的结果。

我只是想向进入网站的人展示数据。我不希望网站以外的任何人访问 Json 文件。

这是我的 express.js

const app = require('express')()
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const fs = require('fs')
const jwt = require('jsonwebtoken')

const PORT = 3002

app.use(cors())
app.use(bodyParser.json())

app.get('/', (req, res) => {
    res.json({message: 'Api'})
  })

  app.post('/api/login',(req, res)=> {
    const user = { id: 3 }
    const token = jwt.sign({ user }, 'our_key')
    res.json({
      token: token
    })
  })

  app.get('/api/protected', ensureToken,(req, res)=>  {
    jwt.verify(req.token, 'our_key',function (err, data) {
      if (err) {
        res.sendStatus(403)
      } else {
        fs.readFile('data.json','utf-8',(err,data)=>{
          res.setHeader("Content-Type", "application/json;     charset=utf-8")
          data = JSON.parse(data)
          console.log(data)
          res.end(JSON.stringify(data,null,4))
      })
      }
    })
  })

  function ensureToken(req, res, next) {
    const bearerHeader = req.headers["authorization"]
    if (typeof bearerHeader !== 'undefined') {
      const bearer = bearerHeader.split(" ")
      const bearerToken = bearer[1]
      req.token = bearerToken
      next()
    } else {
      res.sendStatus(403)
    }
  }

app.listen(PORT, function(){
    console.log('Server http://localhost:'+ PORT + ' OK')  
  })

无论 angular 和 jwt 通过登录/注册系统连接到哪里。没有这个我们能做到吗?

标签: node.jsangularrestexpressjwt

解决方案


在这种情况下,我看到的唯一解决方案如下(老实说,它不是 100% 安全的)

您应该在后端做的第一件事是:

app.use(cors({
     origin: 'http://yourapp.com'
}));

将 cors 限制在其他域。

角度方面的第二部分是让令牌工作并与拦截器端的后端通信。

查看代码后,它应该如下所示:

索引.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Stackoverflow - Test</title>
    <base href="/" />
  </head>
  <body>
    <app-root></app-root>
  </body>
</html>

应用程序模块.ts

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

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { TokenInterceptor } from './data.service';
import { RouterModule, ROUTES } from '@angular/router';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [ {
    provide: HTTP_INTERCEPTORS,
    useClass: TokenInterceptor,
    multi: true,
}],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component, OnInit } from '@angular/core';
import { User } from './data.model';
import { Value } from './data.model';
import { HttpClient } from '@angular/common/http'
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

 users:User[];
 
 constructor(private _http: HttpClient){}

 ngOnInit(){
   this.loadData();
 }

  public async getToken(): Promise<void> {
    console.log('try to get token from api');
    const result: any = await this._http
              .get(`http://localhost:3002/api/login`)
              .toPromise();

    localStorage.setItem('userToken', result.token);
  }

 private async loadData(): Promise<void> {
   if (localStorage.getItem('userToken') == null) {
      await this.getToken();
   }
  
    const result = await this._http.get(`http://localhost:3002/api/protected`)
                .toPromise();

    console.log(result);
 }
}                

和你的 data.service.ts (通常为此目的应该命名为 token.interceptor.ts 或类似的东西。

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
  HttpClient
} from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { User } from './data.model';
import {map, switchMap} from 'rxjs/operators';
@Injectable({
  providedIn: 'root'
})

export class TokenInterceptor implements HttpInterceptor {
  constructor(private _http: HttpClient) {}
  intercept(
      request: HttpRequest<any>,
      next: HttpHandler
  ): Observable<HttpEvent<any>> {
      let currentToken =
          localStorage.getItem('userToken') ||
          sessionStorage.getItem('userToken');
        const authReq = request.clone({
            setHeaders: {
                Authorization: 'Bearer ' + currentToken || []
            }
        });
        return next.handle(authReq);
}
}


推荐阅读