Dylan  Iqbal

Dylan Iqbal

1663816330

MERN Stack Tutorial for Beginners with Full Project

MERN Stack complete course with project include MERN = Nodejs with Expressjs, React with Redux, Mongodb with Mongoose and authentication with passportjs jwt library

What is the MERN stack?

The phrase MERN stack refers to the following technologies:

  • MongoDB, a cross-platform document-oriented database program
  • Express.js, a web application framework for Node.js
  • React, a JavaScript library for building user interfaces
  • Node.js, an open-source, cross-platform JavaScript run-time environment that executes JavaScript code outside of a browser

🌟 Course Contents 🌟
⏳ (00:00:00) Intro to course
⏳ (00:06:38) Course Outline
⏳ (00:11:38) Setup MERN project
⏳ (00:17:38) Setup MongoDB atlas
⏳ (00:25:20) Transaction form
⏳ (00:35:54) Handle CORS & Nodemon
⏳ (00:42:12) API body parser
⏳ (00:47:37) First transaction
⏳ (00:55:24) Fetch all transactions
⏳ (01:02:56) Express routes
⏳ (01:10:58) use material UI
⏳ (01:18:59) Design form 
⏳ (01:25:58) Submit form
⏳ (01:31:33) Transactions table
⏳ (01:40:31) Delete transactions
⏳ (01:52:47) Update design
⏳ (02:02:55) Update API
⏳ (02:09:30) React router dom
⏳ (02:21:53) Register user part 1
⏳ (02:34:10) Register user part 2
⏳ (02:45:50) Login user part 1
⏳ (02:54:18) Login user part 2
⏳ (03:00:14) Passport JWT authenticate
⏳ (03:13:22) DotEnv 
⏳ (03:23:23) Top level component middleware
⏳ (03:34:44) Validate token
⏳ (03:43:36) React redux store
⏳ (03:53:46) Auth store
⏳ (04:06:14) Express controllers
⏳ (04:14:40) Transactions of user
⏳ (04:43:55) Category to transaction
⏳ (04:39:07) Show all category
⏳ (04:46:59) Delete category
⏳ (04:57:12) Update & create category
⏳ (05:10:52) Monthly expense chart
⏳ (05:24:36) Deploy MERN stack to Heroku and Netlify

Source Code: https://github.com/bitfumes/mern-stack-2022


The MERN stack: A Complete Tutorial for Beginners

This tutorial is all about the MERN stack. We’ll outline the basics of the MERN stack and demonstrate how to use it by developing a simple CRUD application from scratch.

Server setup with Express.js and Node.js

To begin our MERN stack tutorial, we’ll show you how to set up a server with Express.js and Node.js.

npm package initialization

To create a project folder, enter the folder through the terminal, then run the following command:

$ npm init

Now it will ask you some questions about package name, version, entry point, etc. Hit enter if you want to keep the default. After that, you will get something like this:

Creating Our package.json File

Select yes and you’re ready to go. It creates a file named package.json.

Installing dependencies

Now, I would like to add some dependencies:

$ npm i express mongoose body-parser bcryptjs validation

Type or copy the command above and hit the enter button. You’ll see something like this:

Adding Project File Dependencies

  • bcryptjs is a password hashing function designed by Niels Provos and David Mazières
  • body-parser allows us to get the data throughout the request
  • express is our main framework
  • mongoose is used to connect/interact with MongoDB
  • validation (as its name implies) is used for validation

Now I want to add nodemon as a dev dependency. If you don’t want to add this, you can skip it — it’s optional.

$ npm i -D nodemon

nodemon is a utility that will monitor for any changes in your source and automatically restart your server.

At that point, your package.json should look like this:

package.json File With Dependencies

Setting the entry point

Now create a file named app.js for our entry point. You can create this from the project folder with the command below (on Mac):

$ touch app.js

Then paste the code below:

// app.js

const express = require('express');

const app = express();

app.get('/', (req, res) => res.send('Hello world!'));

const port = process.env.PORT || 8082;

app.listen(port, () => console.log(`Server running on port ${port}`));

Now, run the command

$ node app

You will see Server running on port 8082. You can also check it from the browser: open the browser and enter http://localhost:8082.

At this point, if we change anything, we need to restart the server manually. But if we set up nodemon, then we don’t have to restart it every time; nodemon will watch if there is any change and restart the server automatically.

So what you need to do for that is a little change to the scripts in our package.json file. See below:

// package.json

{
  "name": "mern_a_to_z",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "app": "nodemon app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/nurislam03/MERN_A_to_Z.git"
  },
  "author": "Nur Islam",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/nurislam03/MERN_A_to_Z/issues"
  },
  "homepage": "https://github.com/nurislam03/MERN_A_to_Z#readme",
  "dependencies": {
    "bcryptjs": "^2.4.3",
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "mongoose": "^5.5.15",
    "validation": "0.0.1"
  },
  "devDependencies": {
    "nodemon": "^1.19.1"
  }
}

So, now you can run your project using this command:

$ npm run app

If you get any error at this point, then run the commands below:

$ npm install
$ npm run app

You will see the following changes in your terminal if everything goes right:

Running Project Successfully

Database management with MongoDB

Now it’s time to work on our MERN database setup with MongoDB. For simplicity, we will use MongoDB Atlas.

Creating an account for MongoDB Atlas

MongoDB Atlas is a fully managed cloud database developed by the same team that built MongoDB.

First, you need an account. Create one and follow the procedure. After creating an account, you will see something like this:

MongoDB Atlas Homescreen

Click on the Project 0 section (top left) and you will see a button for creating a new project. Create a project and select the project.

Now, click on the Build a Cluster button from the project you have created. It will show you all the information. At the bottom, you will see a section called Cluster Name, click on that and enter a name for the database, then hit the Create Cluster button.

After two to three minutes, if everything goes well, you will find something like this:

Creating A Cluster In MongoDB Atlas

Click on the CONNECT button and fill in the username and password form for your database.

Setting Up Our Connection

Now hit the Create MongoDB User button. You can also choose either your current IP address or a different IP address, it’s up to you.

Now, if you follow the CONNECT button or the Choose a connection method button, you will see some different methods. Select accordingly.

Connection Methods Options

In this case, select the Connect Your Application section.

Now you will get your database link, which we will use in our next step.

Connection String Output

Our database is ready — now we need to add it to our project.

Inside the project folder, create another folder named config and inside it create two files named default.json and db.js. Add the following code:

// default.json

{
  "mongoURI":
    "mongodb+srv://mern123:<password>@mernatoz-9kdpd.mongodb.net/test?retryWrites=true&w=majority"
}
 /* Replace <password> with your database password */

/* ------------------------------------------------------------------ */
// db.js

const mongoose = require('mongoose');
const config = require('config');
const db = config.get('mongoURI');

const connectDB = async () => {
  try {
    await mongoose.connect(
      db,
      {
        useNewUrlParser: true
      }
    );

    console.log('MongoDB is Connected...');
  } catch (err) {
    console.error(err.message);
    process.exit(1);
  }
};

module.exports = connectDB;

NOTE: We need a little change in our app.js file to connect to the database. Update your app.js with this:

// app.js

const express = require('express');
const connectDB = require('./config/db');

const app = express();

// Connect Database
connectDB();

app.get('/', (req, res) => res.send('Hello world!'));

const port = process.env.PORT || 8082;

app.listen(port, () => console.log(`Server running on port ${port}`));

We need another dependency package called config for the global variable to run our project. Use the following command to install it to the project:

$ npm i config

Now, you can run the project using the following command:

$ npm run app
Successfully Connected Server

Great! So far we are on the right track. Our database is successfully connected. Now time to complete the route setup, and after that, we will see how to create RESTful APIs.

Building RESTful APIs with the MERN stack

Create a folder named routes. In it, create another folder named api, which will hold all our APIs.

Inside the api folder, create a file named books.js. We will create some APIs here to show how it works in a moment.

Now update your books.js with the following code:

// routes/api/books.js

const express = require('express');
const router = express.Router();

// Load Book model
const Book = require('../../models/Book');

// @route GET api/books/test
// @description tests books route
// @access Public
router.get('/test', (req, res) => res.send('book route testing!'));

// @route GET api/books
// @description Get all books
// @access Public
router.get('/', (req, res) => {
  Book.find()
    .then(books => res.json(books))
    .catch(err => res.status(404).json({ nobooksfound: 'No Books found' }));
});

// @route GET api/books/:id
// @description Get single book by id
// @access Public
router.get('/:id', (req, res) => {
  Book.findById(req.params.id)
    .then(book => res.json(book))
    .catch(err => res.status(404).json({ nobookfound: 'No Book found' }));
});

// @route GET api/books
// @description add/save book
// @access Public
router.post('/', (req, res) => {
  Book.create(req.body)
    .then(book => res.json({ msg: 'Book added successfully' }))
    .catch(err => res.status(400).json({ error: 'Unable to add this book' }));
});

// @route GET api/books/:id
// @description Update book
// @access Public
router.put('/:id', (req, res) => {
  Book.findByIdAndUpdate(req.params.id, req.body)
    .then(book => res.json({ msg: 'Updated successfully' }))
    .catch(err =>
      res.status(400).json({ error: 'Unable to update the Database' })
    );
});

// @route GET api/books/:id
// @description Delete book by id
// @access Public
router.delete('/:id', (req, res) => {
  Book.findByIdAndRemove(req.params.id, req.body)
    .then(book => res.json({ mgs: 'Book entry deleted successfully' }))
    .catch(err => res.status(404).json({ error: 'No such a book' }));
});

module.exports = router;

Database model

In order to interact with our database, we need to create a model for each of our resources. So, create a folder called models in the root, and inside the models folder, create a file called Book.js and update it with this:

// models/Book.js

const mongoose = require('mongoose');

const BookSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  isbn: {
    type: String,
    required: true
  },
  author: {
    type: String,
    required: true
  },
  description: {
    type: String
  },
  published_date: {
    type: Date
  },
  publisher: {
    type: String
  },
  updated_date: {
    type: Date,
    default: Date.now
  }
});

module.exports = Book = mongoose.model('book', BookSchema);

Run the project to see if everything is fine at this point, and you can test all the APIs through Postman (note that before testing APIs using Postman, you need to run the project first). You can download Postman here.

Building the frontend

So far, so good! Now that we’ve set up our backend, it’s time to transition to the frontend part of this MERN stack tutorial.

In this section, we’ll use React to build our user interfaces. React is a JavaScript library for building user interfaces. It is maintained by Facebook and a community of individual developers and other companies.

We’ll use Create React App to generate our initial file setup. CRA is a comfortable environment for learning React and is the best way to start building applications in React. It offers a modern build setup with no configuration.

We’ll also use webpack and Babel to bundle our modules and compile our JavaScript, respectively. If you don’t know webpack or Babel well, no problem; you don’t need to install or configure tools like webpack or Babel. They’re preconfigured and hidden so that you can focus on the code. Just create a project, and you’re good to go.

You’ll also need any version of Node.js greater than 8.10 and any version of npm greater than 5.6 installed on your local development machine.

Setting up Create React App

Set any directory using a terminal where you want to keep all the files of this project and run the following command to get the initial setup file:

 $ npx create-react-app my-app

You can replace my-app with whatever you’d like to use as your project name. For example, my project name is mern_a_to_z_client, and my command is:

 $ npx create-react-app mern_a_to_z_client

Note: The project name must be in lowercase letters.

If everything goes right, then you will see something like the following image, where you will find some instructions along with the commands.

Project Successfully Created In Create React App

Before using any built-in command, we need to go inside the project folder.

 $ cd mern_a_to_z_client

Now that we are in the project directory, we can use those available commands. If you’re using Yarn:

$ yarn start

Or, if using npm:

$ npm start

To run the app in development mode, you can use any of the above commands, and you will see the following message in your terminal.

Running App In Development Mode

Now open http://localhost:3000 to view it in the browser. This page will automatically reload if you make changes to the code.

Viewing Our App In The Browser

Initial project structure

Inside the project directory, our initial file structure should look like this:

Our Initial Project Structure

Adding Bootstrap and Font Awesome to your React app

We have got our initial setup file for the front-end part. Now we can start integrating our back end with our front end. Before that, though, I want to add Bootstrap and Font Awesome’s CDN to our project.

Open the file called index.html, which is in the public folder mern_a_to_z_client/public/index.html, and replace everything with the following code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->

    <!-- bootstrap css cdn -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <!-- fontawesome cdn -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">

    <title>MERN A to Z</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->

    <!-- bootstrap JS cdn -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

  </body>
</html>

Frontend tasks and features

We will work with five different features:

  1. Add, create or save a new book
  2. Show all the books we have stored in the database
  3. Show a single book
  4. Update a book
  5. Delete a book

Dependencies packages installation

Now, use the following command to add some necessary dependencies:

$ npm install --save react-router-dom
$ npm install --save axios

Why Axios?

Axios is a lightweight HTTP client based similar to a Fetch API. Axios is a promise-based async/await library for readable asynchronous code. We can easily integrate with React, and it is effortless to use in any front-end framework.

We’ll call our APIs through Axios.

Package.json file

At this point, our package.json file should be similar to this; versions can be similar or different:

// MERN_A_to_Z_Client - package.json

{
  "name": "mern_a_to_z_client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "axios": "^0.19.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-router-dom": "^5.0.1",
    "react-scripts": "3.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

Creating the component file

Inside the src folder (mern_a_to_z_client/src/), create another folder called components, and inside it, create five different files:

  1. CreateBook.js
  2. ShowBookList.js
  3. BookCard.js
  4. ShowBookDetails.js
  5. UpdateBookInfo.js

We will work with these five files a bit later.

Setup route

Open the folder called App.js inside the src folder (mern_a_to_z_client/src/App.js), and replace it with the following code:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import './App.css';

import CreateBook from './components/CreateBook';
import ShowBookList from './components/ShowBookList';
import ShowBookDetails from './components/ShowBookDetails';
import UpdateBookInfo from './components/UpdateBookInfo';

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Route exact path='/' component={ShowBookList} />
          <Route path='/create-book' component={CreateBook} />
          <Route path='/edit-book/:id' component={UpdateBookInfo} />
          <Route path='/show-book/:id' component={ShowBookDetails} />
        </div>
      </Router>
    );
  }
}

export default App;

Here, we define all the routes. For a specific path definition, its corresponding component will be rendered. We have not implemented these files/components yet — just completed the path setup.

Updating the CSS file

Update a CSS file called App.css in the src folder with the following code:

.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
  pointer-events: none;
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.CreateBook {
  background-color: #2c3e50;
  min-height: 100vh;
  color: white;
}

.ShowBookDetails {
  background-color: #2c3e50;
  min-height: 100vh;
  color: white;
}

.UpdateBookInfo {
  background-color: #2c3e50;
  min-height: 100vh;
  color: white;
}

.ShowBookList {
  background-color: #2c3e50;
  height: 100%;
  width: 100%;
  min-height: 100vh;
  min-width: 100px;
  color: white;
}


/* BookList Styles */
.list {
  display: grid;
  margin: 20px 0 50px 0;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 1fr;
  grid-gap: 2em;
}

.card-container {
  width: 250px;
  border: 1px solid rgba(0,0,.125);
  margin: 0 auto;
  border-radius: 5px;
  overflow: hidden;
}

.desc {
  height: 130px;
  padding: 10px;
}

.desc h2 {
  font-size: 1em;
  font-weight: 400;
}

.desc h3, p {
  font-weight: 300;
}

.desc h3 {
  color: #6c757d;
  font-size: 1em;
  padding: 10px 0 10px 0;
}

Adding our feature components

Now it’s time to add feature components to our MERN stack project.

Create a new book

Our CreateBook.js file is responsible for adding, creating, or saving a new book or a book’s info. So, update CreateBook.js with the following code:

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import '../App.css';
import axios from 'axios';


class CreateBook extends Component {
  constructor() {
    super();
    this.state = {
      title: '',
      isbn:'',
      author:'',
      description:'',
      published_date:'',
      publisher:''
    };
  }

  onChange = e => {
    this.setState({ [e.target.name]: e.target.value });
  };

  onSubmit = e => {
    e.preventDefault();

    const data = {
      title: this.state.title,
      isbn: this.state.isbn,
      author: this.state.author,
      description: this.state.description,
      published_date: this.state.published_date,
      publisher: this.state.publisher
    };

    axios
      .post('http://localhost:8082/api/books', data)
      .then(res => {
        this.setState({
          title: '',
          isbn:'',
          author:'',
          description:'',
          published_date:'',
          publisher:''
        })
        this.props.history.push('/');
      })
      .catch(err => {
        console.log("Error in CreateBook!");
      })
  };

  render() {
    return (
      <div className="CreateBook">
        <div className="container">
          <div className="row">
            <div className="col-md-8 m-auto">
              <br />
              <Link to="/" className="btn btn-outline-warning float-left">
                  Show BooK List
              </Link>
            </div>
            <div className="col-md-8 m-auto">
              <h1 className="display-4 text-center">Add Book</h1>
              <p className="lead text-center">
                  Create new book
              </p>

              <form noValidate onSubmit={this.onSubmit}>
                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Title of the Book'
                    name='title'
                    className='form-control'
                    value={this.state.title}
                    onChange={this.onChange}
                  />
                </div>
                <br />

                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='ISBN'
                    name='isbn'
                    className='form-control'
                    value={this.state.isbn}
                    onChange={this.onChange}
                  />
                </div>

                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Author'
                    name='author'
                    className='form-control'
                    value={this.state.author}
                    onChange={this.onChange}
                  />
                </div>

                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Describe this book'
                    name='description'
                    className='form-control'
                    value={this.state.description}
                    onChange={this.onChange}
                  />
                </div>

                <div className='form-group'>
                  <input
                    type='date'
                    placeholder='published_date'
                    name='published_date'
                    className='form-control'
                    value={this.state.published_date}
                    onChange={this.onChange}
                  />
                </div>
                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Publisher of this Book'
                    name='publisher'
                    className='form-control'
                    value={this.state.publisher}
                    onChange={this.onChange}
                  />
                </div>

                <input
                    type="submit"
                    className="btn btn-outline-warning btn-block mt-4"
                />
              </form>
          </div>
          </div>
        </div>
      </div>
    );
  }
}

export default CreateBook;

Show all books

The ShowBookList.js component will be responsible for showing all the books we already have stored in our database. Update ShowBookList.js with this code:

import React, { Component } from 'react';
import '../App.css';
import axios from 'axios';
import { Link } from 'react-router-dom';
import BookCard from './BookCard';

class ShowBookList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      books: []
    };
  }

  componentDidMount() {
    axios
      .get('http://localhost:8082/api/books')
      .then(res => {
        this.setState({
          books: res.data
        })
      })
      .catch(err =>{
        console.log('Error from ShowBookList');
      })
  };


  render() {
    const books = this.state.books;
    console.log("PrintBook: " + books);
    let bookList;

    if(!books) {
      bookList = "there is no book record!";
    } else {
      bookList = books.map((book, k) =>
        <BookCard book={book} key={k} />
      );
    }

    return (
      <div className="ShowBookList">
        <div className="container">
          <div className="row">
            <div className="col-md-12">
              <br />
              <h2 className="display-4 text-center">Books List</h2>
            </div>

            <div className="col-md-11">
              <Link to="/create-book" className="btn btn-outline-warning float-right">
                + Add New Book
              </Link>
              <br />
              <br />
              <hr />
            </div>

          </div>

          <div className="list">
                {bookList}
          </div>
        </div>
      </div>
    );
  }
}

export default ShowBookList;

Creating a card for each book

Here we use a functional component called BookCard.js, which takes a book’s info from ShowBookList.js and makes a card for each book. Write the following code to update your BookCard.js file:

import React from 'react';
import { Link } from 'react-router-dom';
import '../App.css';

const BookCard = (props) => {
    const  book  = props.book;

    return(
        <div className="card-container">
            <img src="https://commapress.co.uk/books/the-book-of-cairo/cairo-provisional-v3/image%2Fspan3" alt="" />
            <div className="desc">
                <h2>
                    <Link to={`/show-book/${book._id}`}>
                        { book.title }
                    </Link>
                </h2>
                <h3>{book.author}</h3>
                <p>{book.description}</p>
            </div>
        </div>
    )
};

export default BookCard;

NOTE: Here, I used the same img src for each book, since each book’s respective image may not always be available. Change the image source, and you can also use a different image for each book.

Show a book’s info

The ShowBookDetails component has one task: it shows all the info we have about any book. We have both delete and edit buttons here to get access.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import '../App.css';
import axios from 'axios';

class showBookDetails extends Component {
  constructor(props) {
    super(props);
    this.state = {
      book: {}
    };
  }

  componentDidMount() {
    // console.log("Print id: " + this.props.match.params.id);
    axios
      .get('http://localhost:8082/api/books/'+this.props.match.params.id)
      .then(res => {
        // console.log("Print-showBookDetails-API-response: " + res.data);
        this.setState({
          book: res.data
        })
      })
      .catch(err => {
        console.log("Error from ShowBookDetails");
      })
  };

  onDeleteClick (id) {
    axios
      .delete('http://localhost:8082/api/books/'+id)
      .then(res => {
        this.props.history.push("/");
      })
      .catch(err => {
        console.log("Error form ShowBookDetails_deleteClick");
      })
  };


  render() {

    const book = this.state.book;
    let BookItem = <div>
      <table className="table table-hover table-dark">
        {/* <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col">First</th>
            <th scope="col">Last</th>
            <th scope="col">Handle</th>
          </tr>
        </thead> */}
        <tbody>
          <tr>
            <th scope="row">1</th>
            <td>Title</td>
            <td>{ book.title }</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Author</td>
            <td>{ book.author }</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>ISBN</td>
            <td>{ book.isbn }</td>
          </tr>
          <tr>
            <th scope="row">4</th>
            <td>Publisher</td>
            <td>{ book.publisher }</td>
          </tr>
          <tr>
            <th scope="row">5</th>
            <td>Published Date</td>
            <td>{ book.published_date }</td>
          </tr>
          <tr>
            <th scope="row">6</th>
            <td>Description</td>
            <td>{ book.description }</td>
          </tr>
        </tbody>
      </table>
    </div>

    return (
      <div className="ShowBookDetails">
        <div className="container">
          <div className="row">
            <div className="col-md-10 m-auto">
              <br /> <br />
              <Link to="/" className="btn btn-outline-warning float-left">
                  Show Book List
              </Link>
            </div>
            <br />
            <div className="col-md-8 m-auto">
              <h1 className="display-4 text-center">Book's Record</h1>
              <p className="lead text-center">
                  View Book's Info
              </p>
              <hr /> <br />
            </div>
          </div>
          <div>
            { BookItem }
          </div>

          <div className="row">
            <div className="col-md-6">
              <button type="button" className="btn btn-outline-danger btn-lg btn-block" onClick={this.onDeleteClick.bind(this,book._id)}>Delete Book</button><br />
            </div>

            <div className="col-md-6">
              <Link to={`/edit-book/${book._id}`} className="btn btn-outline-info btn-lg btn-block">
                    Edit Book
              </Link>
              <br />
            </div>

          </div>
            {/* <br />
            <button type="button" class="btn btn-outline-info btn-lg btn-block">Edit Book</button>
            <button type="button" class="btn btn-outline-danger btn-lg btn-block">Delete Book</button> */}

        </div>
      </div>
    );
  }
}

export default showBookDetails;

Update a book’s info

UpdateBookInfo.js, as its name indicates, is responsible for updating a book’s info. An Edit Book button will trigger this component to perform. After clicking Edit Book, we will see a form with the old info, which we will be able to edit or replace.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
import '../App.css';

class UpdateBookInfo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      title: '',
      isbn: '',
      author: '',
      description: '',
      published_date: '',
      publisher: ''
    };
  }

  componentDidMount() {
    // console.log("Print id: " + this.props.match.params.id);
    axios
      .get('http://localhost:8082/api/books/'+this.props.match.params.id)
      .then(res => {
        // this.setState({...this.state, book: res.data})
        this.setState({
          title: res.data.title,
          isbn: res.data.isbn,
          author: res.data.author,
          description: res.data.description,
          published_date: res.data.published_date,
          publisher: res.data.publisher
        })
      })
      .catch(err => {
        console.log("Error from UpdateBookInfo");
      })
  };

  onChange = e => {
    this.setState({ [e.target.name]: e.target.value });
  };

  onSubmit = e => {
    e.preventDefault();

    const data = {
      title: this.state.title,
      isbn: this.state.isbn,
      author: this.state.author,
      description: this.state.description,
      published_date: this.state.published_date,
      publisher: this.state.publisher
    };

    axios
      .put('http://localhost:8082/api/books/'+this.props.match.params.id, data)
      .then(res => {
        this.props.history.push('/show-book/'+this.props.match.params.id);
      })
      .catch(err => {
        console.log("Error in UpdateBookInfo!");
      })
  };


  render() {
    return (
      <div className="UpdateBookInfo">
        <div className="container">
          <div className="row">
            <div className="col-md-8 m-auto">
              <br />
              <Link to="/" className="btn btn-outline-warning float-left">
                  Show BooK List
              </Link>
            </div>
            <div className="col-md-8 m-auto">
              <h1 className="display-4 text-center">Edit Book</h1>
              <p className="lead text-center">
                  Update Book's Info
              </p>
            </div>
          </div>

          <div className="col-md-8 m-auto">
          <form noValidate onSubmit={this.onSubmit}>
            <div className='form-group'>
              <label htmlFor="title">Title</label>
              <input
                type='text'
                placeholder='Title of the Book'
                name='title'
                className='form-control'
                value={this.state.title}
                onChange={this.onChange}
              />
            </div>
            <br />

            <div className='form-group'>
            <label htmlFor="isbn">ISBN</label>
              <input
                type='text'
                placeholder='ISBN'
                name='isbn'
                className='form-control'
                value={this.state.isbn}
                onChange={this.onChange}
              />
            </div>

            <div className='form-group'>
            <label htmlFor="author">Author</label>
              <input
                type='text'
                placeholder='Author'
                name='author'
                className='form-control'
                value={this.state.author}
                onChange={this.onChange}
              />
            </div>

            <div className='form-group'>
            <label htmlFor="description">Description</label>
              <input
                type='text'
                placeholder='Describe this book'
                name='description'
                className='form-control'
                value={this.state.description}
                onChange={this.onChange}
              />
            </div>

            <div className='form-group'>
            <label htmlFor="published_date">Published Date</label>
              <input
                type='date'
                placeholder='published_date'
                name='published_date'
                className='form-control'
                value={this.state.published_date}
                onChange={this.onChange}
              />
            </div>
            <div className='form-group'>
            <label htmlFor="publisher">Publisher</label>
              <input
                type='text'
                placeholder='Publisher of this Book'
                name='publisher'
                className='form-control'
                value={this.state.publisher}
                onChange={this.onChange}
              />
            </div>

            <button type="submit" className="btn btn-outline-info btn-lg btn-block">Update Book</button>
            </form>
          </div>

        </div>
      </div>
    );
  }
}

export default UpdateBookInfo;

Connecting the frontend to the backend

We just implemented all of our components! Now we need a little change in our server-side (back-end) project.

Changes required on the backend

If we try to call our back-end API from the front-end part, it gets an error that says: “Access to XMLHttpRequest at ‘http://localhost:8082/api/books&#8217; from origin ‘http://localhost:3000&#8217; has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”

To solve this, we need to install cors in our back-end (server-side) project. Go to the project folder (e.g., MERN_A_to_Z) and run:

$ npm install cors

Now, update app.js (the back end’s entry point) with the following code:

// app.js

const express = require('express');
const connectDB = require('./config/db');
var cors = require('cors');

// routes
const books = require('./routes/api/books');

const app = express();

// Connect Database
connectDB();

// cors
app.use(cors({ origin: true, credentials: true }));

// Init Middleware
app.use(express.json({ extended: false }));

app.get('/', (req, res) => res.send('Hello world!'));

// use Routes
app.use('/api/books', books);

const port = process.env.PORT || 8082;

app.listen(port, () => console.log(`Server running on port ${port}`));

Running the frontend and backend

Follow the steps below to run both the frontend and backend of our MERN stack example.

Run the server

Now, run the server (inside the project folder):

$ npm run app

If you get any error, then follow the commands below (inside the project folder):

$ npm install
$ npm run app

Run the client

From the front-end project directory, run the command below:

$ npm start

If you get an error, again, follow the same commands below:

$ npm install
$ npm start

Testing our MERN stack app in the browser

Let’s check everything in the browser. Open http://localhost:3000 in your browser. Now you can add a book, delete a book, show the list of books, and edit books. The following routes should perform accordingly:

Add a new book: http://localhost:3000/create-book

The Add Book Page

Show the list of books: http://localhost:3000/

The Books List Page

Show any book’s info: http://localhost:3000/show-book/:id

Show Book Details Page

Update a book’s info: http://localhost:3000/edit-book/:id

The Edit Book Page

Congratulations! You have successfully completed this MERN stack tutorial.

You can visit my GitHub to see both the server-side and client-side portions of this MERN stack tutorial. You can also find the complete repo for our MERN stack example app on GitHub.

#mern #mongodb #react #expressjs #node #redux #mongoose #jwt #passportjs 

MERN Stack Tutorial for Beginners with Full Project

Autenticação com Node.js e MongoDB com JWT - Login e Registro com Node.js

Neste vídeo você vai aprender a criar uma API de autenticação com: Node.js, Express, MongoDB (Mongoose) e que gerencia tokens por WT

Criaremos rotas públicas e privadas, para que possamos validar a presença da autorização do token

Que vai impedir quem não possui de acessar recursos privados, porém pode acessar endpoints públicos

Além disso vamos inserir os usuários no banco de dados MongoDB, com auxílio da ODM Mongoose

A API será feita com base no Node.js, utilizando o framework Express

Arquivos deste curso:  https://github.com/matheusbattisti/curso_node/tree/main/18_AUTH_NODE_JWT

#nodejs #jwt #mongodb 

Autenticação com Node.js e MongoDB com JWT - Login e Registro com Node.js
Reid  Rohan

Reid Rohan

1661854740

Cognito-Express: API Authentication with AWS Congito

Cognito-Express: API Authentication with AWS Congito

Synopsis

cognito-express authenticates API requests on a Node.js application (either running on a server or in an AWS Lambda function) by verifying the JWT signature of AccessToken or IDToken generated by Amazon Cognito.

Architecture

Motivation

Architecture

This module lets you authenticate Node.js API requests by verifying the JWT signature of AccessToken or IDToken - without needing to call Amazon Cognito for each API invocation.

The module can be easily and unobtrusively integrated into any application or framework that supports Connect-style middleware, including Express.

This module essentially bundles steps 1-7 listed on the official AWS documentation on Using ID Tokens and Access Tokens in your Web APIs

  1. Download and store the JSON Web Token (JWT) set for your user pool.
  2. Decode the token string into JWT format.
  3. Check the iss claim. It should match your user pool.
  4. Check the tokenUse claim. It should match your set preference for access or id token types
  5. Get the kid from the JWT token header and retrieve the corresponding JSON Web Key that was stored in step 1.
  6. Verify the signature of the decoded JWT token.
  7. Check the exp claim and make sure the token is not expired.

You can now trust the claims inside the token and use it as it fits your requirements.

Prerequisites

After successful authentication of a user, Amazon Cognito issues three tokens to the client:

  • ID token
  • Access token
  • Refresh token

(Note: The login mechanism is not covered by this module and you'll have to build that separately)

Save these tokens within the client app (preferably as cookies). When any API is invoked from client, pass in the AccessToken or IDToken to the server.

It's completely up to you how you pass in the AccessToken or IDToken. Here are two options:

  1. By adding them explicitly in Request Headers
  2. Just save the tokens as cookies. This way they get attached to request headers whenever APIs are invoked.

Configuration

//Initializing CognitoExpress constructor
const cognitoExpress = new CognitoExpress({
    region: "us-east-1",
    cognitoUserPoolId: "us-east-1_dXlFef73t",
    tokenUse: "access", //Possible Values: access | id
    tokenExpiration: 3600000 //Up to default expiration of 1 hour (3600000 ms)
});

Usage

cognitoExpress.validate(accessTokenFromClient, function(err, response) {
    if (err) {
        /*
            //API is not authenticated, do something with the error.
            //Perhaps redirect user back to the login page
            
            //ERROR TYPES:
            
            //If accessTokenFromClient is null or undefined
            err = {
                "name": "TokenNotFound",
                "message": "access token not found"
            }
            
            //If tokenuse doesn't match accessTokenFromClient
            {
                "name": "InvalidTokenUse",
                "message": "Not an id token"
            }

            //If token expired
            err = {
                "name": "TokenExpiredError",
                "message": "jwt expired",
                "expiredAt": "2017-07-05T16:41:59.000Z"
            }

            //If token's user pool doesn't match the one defined in constructor
            {
                "name": "InvalidUserPool",
                "message": "access token is not from the defined user pool"
            }

        */
    } else {
        //Else API has been authenticated. Proceed.
        res.locals.user = response; //Optional - if you want to capture user information
        next();
    }
});

Also supports async/await pattern

(async function main() {
  try {
    const response = await cognitoExpress.validate(accessTokenFromClient);
    console.log(response);
     //User is authenticated, proceed with rest of your business logic.

  } catch (e) {
    console.error(e);
     //User is not authenticated, do something with the error.
     //Perhaps redirect user back to the login page
  }
})();

Full Example

app.js - server

//app.js
"use strict";

const express = require("express"),
    CognitoExpress = require("cognito-express"),
    port = process.env.PORT || 8000;

const app = express(),
    authenticatedRoute = express.Router(); //I prefer creating a separate Router for authenticated requests

app.use("/api", authenticatedRoute);

//Initializing CognitoExpress constructor
const cognitoExpress = new CognitoExpress({
    region: "us-east-1",
    cognitoUserPoolId: "us-east-1_dXlFef73t",
    tokenUse: "access", //Possible Values: access | id
    tokenExpiration: 3600000 //Up to default expiration of 1 hour (3600000 ms)
});

//Our middleware that authenticates all APIs under our 'authenticatedRoute' Router
authenticatedRoute.use(function(req, res, next) {
    
    //I'm passing in the access token in header under key accessToken
    let accessTokenFromClient = req.headers.accesstoken;

    //Fail if token not present in header. 
    if (!accessTokenFromClient) return res.status(401).send("Access Token missing from header");

    cognitoExpress.validate(accessTokenFromClient, function(err, response) {
        
        //If API is not authenticated, Return 401 with error message. 
        if (err) return res.status(401).send(err);
        
        //Else API has been authenticated. Proceed.
        res.locals.user = response;
        next();
    });
});


//Define your routes that need authentication check
authenticatedRoute.get("/myfirstapi", function(req, res, next) {
    res.send(`Hi ${res.locals.user.username}, your API call is authenticated!`);
});

app.listen(port, function() {
    console.log(`Live on port: ${port}!`);
});

client.js - angular example

//client.js - angular example

"use strict";

//I stored my access token value returned from Cognito in a cookie called ClientAccessToken

app.controller("MyFirstAPI", function($scope, $http, $cookies) {
    $http({
        method: "GET",
        url: "/api/myfirstapi",
        headers: {
            accesstoken: $cookies.get("ClientAccessToken") 
            }
        }
    }).then(
        function success(response) {
            //Authenticated. Do something with the response. 
        },
        function error(err) {
            console.error(err);
        }
    );
});

Contributors

Gary Arora

Download Details:

Author: ghdna
Source Code: https://github.com/ghdna/cognito-express 
License: MIT license

#javascript #express #nodejs #aws #jwt 

Cognito-Express: API Authentication with AWS Congito
高橋  花子

高橋 花子

1661099520

Go での JWT 認証のガイド

JSON Web トークン (JWT) は、オンライン認証を処理するための一般的な方法であり、JWT 認証は任意のサーバー側プログラミング言語で実装できます。

一般的な JWT の背景知識については、これらの記事で、JWT、ベスト プラクティス、および JWT を使用した RESTful API の保護についてさらに学ぶことをお勧めします。

golang-jwtこの記事は、パッケージを使用して Go Web アプリケーションに JWT 認証の実装を開始できるようにすることを目的としています。

このgolang-jwt パッケージは、その機能と使いやすさから、Go で JWT を実装するための最も人気のあるパッケージです。このgolang-jwtパッケージは、JWT を生成および検証するための機能を提供します。

前提条件

このチュートリアルを最大限に活用するには、これらの基本的な要件を満たす必要があります。

  • Go 1.16 以降がマシンにインストールされている (セキュリティ上の理由から)
  • Go またはその他の言語での Web アプリケーションの構築経験 (オプション)

Golang-JWT パッケージの概要

Go ワークスペースをセットアップし、Go モジュール ファイルを初期化したら、ワークスペース ディレクトリのターミナルで次のコマンドを実行して、パッケージgo.modをインストールします。golang-jwt

go get github.com/golang-jwt/jwt

をインストールしたらgolang-jwt、Go ファイルを作成し、これらのパッケージとモジュールをインポートします。

import (
   "log"
    "encoding/json"
   "github.com/golang-jwt/jwt"
   "net/http"
   "time"
)

このチュートリアルでは、これらのパッケージを使用してエラーをログに記録し、サーバーをセットアップし、トークンの有効期限を設定します。

Go での Web サーバーのセットアップ

JWT で保護されるエンドポイントを持つ単純な Web サーバーの作成から始めましょう。

func main() {
   http.HandleFunc("/home", handlePage)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      log.Println("There was an error listening on port :8080", err)
   }

}

メイン関数は、セットアップするハンドラー関数handlePageを使用してホーム エンドポイントをセットアップします。このhandlePage関数は、JWT を使用してページを保護します。サーバーはポートでリッスンするように設定されて:8080いますが、任意のポートを使用できます。

handlePageハンドラー関数は、リクエスト本文がエンコードされた後にリクエストが承認された場合、構造体のエンコードされた JSON をクライアントへのレスポンスとして返しますMessage

type Message struct {
        Status string `json:"status"`
        Info   string `json:"info"`
}

func handlePage(writer http.ResponseWriter, request *http.Request) {
        writer.Header().Set("Content-Type", "application/json")
        var message Message
        err := json.NewDecoder(request.Body).Decode(&message)
        if err != nil {
                return
        }
        err = json.NewEncoder(writer).Encode(message)
        if err != nil {
                return
        }
}

このhandlePage時点では、関数は認証されておらず、ページへのリクエストは自由に機能します。このチュートリアルの後半で、ハンドラー関数に認証を追加する方法を学習します。

API ネットワーク ページ

パッケージを使用した認証用の JWT の生成Golang-JWT

golang-jwtパッケージを使用して JWT トークンを生成するには、秘密鍵が必要です。このチュートリアルの秘密鍵の例を次に示します。ただし、秘密鍵には暗号的に安全な文字列を使用し、環境変数ファイル (.env) からロードする必要があります。

Go アプリケーションで環境変数を使用する方法については、この記事をご覧ください。

var sampleSecretKey = []byte("SecretYouShouldHide")

JWT に使用する秘密鍵を持っている人は誰でも、アプリケーションのユーザーを認証できることに注意してください。このsampleSecretKey場合、変数は秘密鍵を保持します。

JWT トークンを生成する関数を次に示します。関数は文字列とエラーを返す必要があります。JWT の生成中にエラーが発生した場合、関数は空の文字列とエラーを返します。エラーがない場合、関数は JWT 文字列とnil型を返します。

func generateJWT() (string, error) {

}

NewJWT パッケージのメソッドを使用して、新しいトークンを作成できます。このNewメソッドは、署名メソッド (JWT の暗号化アルゴリズム) を受け取り、JWT トークンを返します。

token := jwt.New(jwt.SigningMethodEdDSA)

ClaimsJWT を変更する場合は、トークンのメソッドを使用できます。

claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = "username"

timeこの場合、モジュールとユーザー名と承認ステータスを使用して、JWT の有効期限 (10 分) を設定しています。JWT を検証しようとすると、クレームを取得できます。

JWT 生成の最後の部分は、秘密鍵を使用して文字列に署名することです。SignedStringトークンのメソッドを使用して、トークン文字列に署名できます。このSignedStringメソッドは秘密鍵を受け取り、署名されたトークン文字列を返します。

tokenString, err := token.SignedString(sampleSecretKey)
if err != nil {
    return "", err
 }

 return tokenString, nil

トークンの署名でエラーが発生した場合は、空の文字列とエラーを返すことができます。
Cookie とは異なり、JWT を保存する必要はありません。必要なのは、トークンを検証するための署名キーだけです。

JWT トークンの検証

JWT を検証する従来の方法では、ミドルウェア (操作のために他のハンドラー関数を取り込むハンドラー関数) を使用します。ミドルウェアを使用して、リクエストが承認されていることを確認する方法は次のとおりです。

func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {

}

verifyJWT関数は検証したいリクエストのハンドラ関数を取り込むミドルウェアです。ハンドラー関数は、要求ヘッダーのトークン パラメーターを使用して要求を検証し、ステータスに基づいて応答します。

 return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

})

リクエストが承認された場合、関数はパラメーターとして渡されたverifyJWTハンドラー関数を返します。

JWT を検証するための最初のステップは、リクエストのヘッダー内のトークンを検査することです。

if request.Header["Token"] != nil {

}

トークンがある場合は、トークンの検証とクレームの検証に進むことができます。

トークンを解析する必要があり、パッケージのParseメソッドを使用してトークンを解析できます。jwtこのparseメソッドは、トークンと JWT デコレーター関数を受け取り、インターフェイスとエラーを返します。

トークンのメソッドを使用して署名を検証するには、トークンを生成したときにトークンに署名するために使用したのと同じ署名メソッドを使用する必要がありMethodます。この場合、署名方式はECDSA方式でした。

token, err := jwt.Parse(request.Header\["Token"\][0], func(token *jwt.Token) (interface{}, error) {
            _, ok := token.Method.(*jwt.SigningMethodECDSA)
            if !ok {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err := writer.Write([]byte("You're Unauthorized!"))
               if err != nil {
                  return nil, err

               }
            }
            return "", nil

         })

署名の検証に失敗した場合 (関数が を返す場合!ok)、StatusUnauthorizedヘッダーをクライアントに返すことができます。

if err != nil {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err2 := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
              if err2 != nil {
                      return
                }
}

上記のコードでは、トークンの解析中にエラーが発生しています。したがって、ユーザーは無許可であり、メッセージを書き込んで無許可ステータスを返すことができます。

Validトークンのメソッドを使用して、トークンを検証できます。

if token.Valid {
                      endpointHandler(writer, request)
                        } else {
                                writer.WriteHeader(http.StatusUnauthorized)
                                _, err := writer.Write([]byte("You're Unauthorized due to invalid token"))
                                if err != nil {
                                        return
                                }
}

トークンが有効な場合は、ミドルウェア関数のハンドラー関数のパラメーターwriterとパラメーターを使用してエンドポイント ハンドラーを渡して、エンドポイントを返すことができます。request

elseクライアントのリクエストのヘッダーにトークンがない場合のステートメントは次のとおりです。

else {
          writer.WriteHeader(http.StatusUnauthorized)
          _, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
           if err != nil {
               return
           }
}

ミドルウェアを使用しているため、ルート宣言verifyJWTのハンドラー関数は、ルートのハンドラー関数を引数として持つミドルウェアになります。

http.HandleFunc("/home", verifyJWT(handlePage))

検証関数をルートに追加すると、エンドポイントが認証されます。

エンドポイント認証済み

クライアント側では、クライアントは発行されたトークンを提供する必要があります。関数を使用してgenerateJWTリクエストにトークンを追加する関数を次に示します。

func authPage(writer http.ResponseWriter, ) {
        token, err := generateJWT()
        if err != nil {
                        return
        } 
        client := &http.Client{}
        request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
        request.Header.Set("Token", token)
        _, _ = client.Do(request)

}

authPage関数では、変数は関数tokenからのトークンを保持しますgenerateJWTClientパッケージのタイプへの参照を使用してhttp、新しいクライアントを作成し、エンドポイントに要求を行うことができます。request変数はリクエスト インスタンスであり、リクエスト インスタンスのメソッドのメソッドを使用して、上記Setheaderようにリクエスト ヘッダーにトークンを設定できます。

また、トークンを Cookie として設定し、クライアントが認証されたエンドポイントに要求を行うたびに検証のためにトークンを取得することもできます。

JWT トークンからクレームを抽出する

JWT を生成するときに、トークンに情報を埋め込むことを選択できます。関数では、変数をマップにgenerateJWT追加しました。usernameclaims

例としてクレームを使用して、クレームを抽出する方法をusername次に示します。トークン署名を検証するときに、ミドルウェアを使用するか、検証関数に機能を追加できます。

func extractClaims(_ http.ResponseWriter, request *http.Request) (string, error) {
        if request.Header["Token"] != nil {
                tokenString := request.Header\["Token"\][0]
                token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

          if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
                return nil, fmt.Errorf("there's an error with the signing method")
          }
                return sampleSecretKey, nil

            })

            if err != nil {
                        return "Error Parsing Token: ", err
                }
}

関数では、プロセスは関数extractClaimsと同じverifyJWTです。ヘッダーからトークンを取得し、トークンを解析し、署名を検証しました。

claims, ok := token.Claims.(jwt.MapClaims)
          if ok && token.Valid {
                username := claims["username"].(string)
                return username, nil
          }

        }
        return "unable to extract claims", nil

トークンを検証すると、上記のように、Claimsメソッドを使用してクレームを取得し、クレーム マップを使用して JWT のデータを取得できます。

結論

golang-jwtこのチュートリアルでは、パッケージを使用して、JWT 認証を使用して、Go で JSON Web トークンを使用して API と Web ページのエンドポイントを認証する方法を説明しました。このチュートリアルの完全なコードは、Github Gistとして見つけることができます。

秘密鍵に環境変数を使用することを忘れないでください。また、機密データを JWT に隠さないでください。LogRocket ブログには多くの JWT チュートリアルがあり、興味のある言語やフレームワークの使用を開始するためにチェックできます。

ソース: https://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

Go での JWT 認証のガイド
顾 静

顾 静

1661099400

Go 中 JWT 身份验证指南

JSON Web 令牌 (JWT) 是处理在线身份验证的流行方法,您可以使用任何服务器端编程语言实现 JWT 身份验证。

对于一般的 JWT 阅读背景,我建议通过这些文章了解更多关于 JWT、最佳实践以及使用 JWT 保护 RESTful API 的信息。

本文旨在帮助您开始使用该golang-jwt包在您的 Go Web 应用程序中实现 JWT 身份验证。

golang-jwt 由于其特性和易用性,该包是在 Go 中实现 JWT 最流行的包。该golang-jwt包提供了生成和验证 JWT 的功能。

先决条件

您需要满足这些基本要求才能充分利用本教程。

  • 在您的机器上安装 Go 1.16 或更高版本(出于安全原因)
  • 使用 Go 或任何其他语言构建 Web 应用程序的经验(可选)

Golang-JWT 包入门

设置好 Go 工作区并初始化 Go 模块文件go.mod后,在终端上的工作区目录中运行以下命令以安装golang-jwt包:

go get github.com/golang-jwt/jwt

安装后golang-jwt,创建一个 Go 文件并导入这些包和模块。

import (
   "log"
    "encoding/json"
   "github.com/golang-jwt/jwt"
   "net/http"
   "time"
)

您将在本教程中使用这些包来记录错误、设置服务器和设置令牌过期时间。

在 Go 中设置 Web 服务器

让我们从创建一个简单的 Web 服务器开始,该服务器的端点将由 JWT 保护。

func main() {
   http.HandleFunc("/home", handlePage)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      log.Println("There was an error listening on port :8080", err)
   }

}

主函数使用handlePage您将设置的处理程序函数设置主端点。该handlePage函数将使用 JWT 保护页面。服务器设置为侦听端口:8080,但您可以使用您选择的任何端口。

如果在请求正文编码后请求被授权,则处理函数将返回结构的编码 JSON 作为对客户端的响应handlePageMessage

type Message struct {
        Status string `json:"status"`
        Info   string `json:"info"`
}

func handlePage(writer http.ResponseWriter, request *http.Request) {
        writer.Header().Set("Content-Type", "application/json")
        var message Message
        err := json.NewDecoder(request.Body).Decode(&message)
        if err != nil {
                return
        }
        err = json.NewEncoder(writer).Encode(message)
        if err != nil {
                return
        }
}

此时,该handlePage功能尚未经过身份验证,向页面发出请求将可以自由工作。您将在本教程的后面部分学习如何向处理程序函数添加身份验证。

API网络页面

使用包生成 JWT 进行身份验证Golang-JWT

您将需要一个密钥来使用该golang-jwt包生成 JWT 令牌。这是本教程的示例私钥;但是,您应该为您的密钥使用加密安全字符串,并从环境变量文件 (.env) 中加载它。

查看这篇文章,了解如何在 Go 应用程序中使用环境变量。

var sampleSecretKey = []byte("SecretYouShouldHide")

请注意,任何拥有您用于 JWT 的密钥的人都可以对您的应用程序的用户进行身份验证。在这种sampleSecretKey情况下,变量保存私钥。

这是一个生成 JWT 令牌的函数。该函数应返回一个字符串和一个错误。如果生成 JWT 时出错,该函数将返回一个空字符串和错误。如果没有错误,该函数将返回 JWT 字符串和nil类型。

func generateJWT() (string, error) {

}

New您可以使用JWT 包的方法创建新令牌。该New方法采用签名方法(JWT 的加密算法)并返回 JWT 令牌。

token := jwt.New(jwt.SigningMethodEdDSA)

如果要修改JWT,可以使用Claimstoken的方法。

claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = "username"

在这种情况下,您将使用time模块以及用户名和授权状态为 JWT 设置过期时间,即十分钟。在尝试验证 JWT 时,您将能够检索声明。

生成 JWT 的最后一部分是使用您的密钥对字符串进行签名。您可以使用令牌的SignedString方法对令牌字符串进行签名。该SignedString方法采用密钥并返回签名的令牌字符串。

tokenString, err := token.SignedString(sampleSecretKey)
if err != nil {
    return "", err
 }

 return tokenString, nil

如果签署令牌时出现错误,您可以返回空字符串和错误。
不像cookies,你不需要存储JWT;您所需要的只是您的签名密钥来验证令牌。

验证 JWT 令牌

验证 JWT 的传统方法使用中间件(处理函数接受其他处理函数进行操作)。下面介绍如何使用中间件来验证请求是否被授权。

func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {

}

verifyJWT函数是一个中间件,它接收您要验证的请求的处理函数。处理函数使用请求标头中的令牌参数来验证请求并根据状态进行响应。

 return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

})

如果请求被授权,该verifyJWT函数返回作为参数传入的处理函数。

验证 JWT 的第一步是检查请求标头中的令牌。

if request.Header["Token"] != nil {

}

如果有令牌,您可以继续验证令牌并验证声明。

您必须解析令牌,并且可以使用包的Parse方法解析令牌jwt。该parse方法接受令牌和 JWT 装饰器函数并返回接口和错误。

您需要使用生成令牌时用于签名令牌的相同签名方法,以使用令牌的Method方法验证签名。在这种情况下,签名方法是ECDSA方法。

token, err := jwt.Parse(request.Header\["Token"\][0], func(token *jwt.Token) (interface{}, error) {
            _, ok := token.Method.(*jwt.SigningMethodECDSA)
            if !ok {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err := writer.Write([]byte("You're Unauthorized!"))
               if err != nil {
                  return nil, err

               }
            }
            return "", nil

         })

如果签名验证失败(函数返回!ok),您可以StatusUnauthorized向客户端返回一个标头。

if err != nil {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err2 := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
              if err2 != nil {
                      return
                }
}

在上面的代码中,解析令牌时出错。因此,用户是未经授权的,您可以编写消息并返回未经授权的状态。

您可以使用令牌的Valid方法来验证令牌。

if token.Valid {
                      endpointHandler(writer, request)
                        } else {
                                writer.WriteHeader(http.StatusUnauthorized)
                                _, err := writer.Write([]byte("You're Unauthorized due to invalid token"))
                                if err != nil {
                                        return
                                }
}

如果令牌有效,您可以将端点处理程序与处理函数的writerrequest参数一起传递给中间件函数以返回端点。

以下是else客户端请求的标头中没有令牌的情况的语句:

else {
          writer.WriteHeader(http.StatusUnauthorized)
          _, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
           if err != nil {
               return
           }
}

由于您使用的是中间件,因此路由声明中的处理函数将是verifyJWT中间件,其中路由的处理函数作为参数。

http.HandleFunc("/home", verifyJWT(handlePage))

将验证功能添加到路由后,端点就会通过身份验证。

端点认证

在客户端,客户端必须提供已发布的令牌。这是一个使用该generateJWT函数在请求中添加令牌的函数。

func authPage(writer http.ResponseWriter, ) {
        token, err := generateJWT()
        if err != nil {
                        return
        } 
        client := &http.Client{}
        request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
        request.Header.Set("Token", token)
        _, _ = client.Do(request)

}

authPage函数中,token变量保存来自函数的标记generateJWT。使用Client对包类型的引用http,您可以创建一个新客户端并向端点发出请求。request变量是请求实例,并且 - 使用请求实例的方法Setheader方法 - 您可以在请求标头中设置令牌,如上所示。

您还可以选择将令牌设置为 cookie,并在客户端向经过身份验证的端点发出请求时检索它以进行验证。

从 JWT 令牌中提取声明

在生成 JWT 时,您可以选择在令牌中嵌入信息。在generateJWT函数中,您将username变量添加到claims地图中。

以下是提取声明的方法,以username声明为例。验证令牌签名时,您可以使用中间件或将功能添加到验证函数中。

func extractClaims(_ http.ResponseWriter, request *http.Request) (string, error) {
        if request.Header["Token"] != nil {
                tokenString := request.Header\["Token"\][0]
                token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

          if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
                return nil, fmt.Errorf("there's an error with the signing method")
          }
                return sampleSecretKey, nil

            })

            if err != nil {
                        return "Error Parsing Token: ", err
                }
}

extractClaims函数中,过程与verifyJWT函数相同;您从标头中检索了令牌,解析了令牌并验证了签名。

claims, ok := token.Claims.(jwt.MapClaims)
          if ok && token.Valid {
                username := claims["username"].(string)
                return username, nil
          }

        }
        return "unable to extract claims", nil

在验证令牌时,您可以使用该Claims方法检索声明,并使用声明映射来检索 JWT 中的数据,如上所示。

结论

本教程教您如何使用 JWT 身份验证通过使用 JSON Web Tokens 包在 Go 中对 API 和网页端点进行身份验证golang-jwt。您可以在本教程中以Github Gist的形式找到完整的代码。

请记住为您的密钥使用环境变量,并且不要在 JWT 中隐藏敏感数据。LogRocket 博客上有许多 JWT 教程,您可以查看这些教程以开始使用您感兴趣的语言或框架!

来源:https ://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

Go 中 JWT 身份验证指南
Hoang  Kim

Hoang Kim

1661095680

Hướng Dẫn Xác Thực JWT Trong Go

Mã thông báo web JSON (JWT) là một phương pháp phổ biến để xử lý xác thực trực tuyến và bạn có thể triển khai xác thực JWT bằng bất kỳ ngôn ngữ lập trình phía máy chủ nào.

Để đọc nền tảng về JWT nói chung, tôi khuyên bạn nên tìm hiểu thêm về JWT, các phương pháp hay nhất và bảo mật API RESTful với JWT với các bài viết này.

Bài viết này nhằm giúp bạn bắt đầu triển khai xác thực JWT trong các ứng dụng web Go của bạn bằng cách sử dụng golang-jwtgói.

Gói golang-jwt này là gói phổ biến nhất để triển khai JWT trong Go, do các tính năng của nó và dễ sử dụng. Gói golang-jwtnày cung cấp chức năng để tạo và xác thực JWT.

Điều kiện tiên quyết

Bạn sẽ cần đáp ứng các yêu cầu cơ bản này để tận dụng tối đa hướng dẫn này.

  • Phiên bản 1.16 trở lên được cài đặt trên máy của bạn (vì lý do bảo mật )
  • Trải nghiệm xây dựng ứng dụng web bằng Go hoặc bất kỳ ngôn ngữ nào khác (tùy chọn)

Bắt đầu với gói Golang-JWT

Sau khi thiết lập không gian làm việc Go của bạn và khởi tạo tệp mô-đun Go go.mod, hãy chạy lệnh này trên thiết bị đầu cuối của bạn trong thư mục không gian làm việc để cài đặt golang-jwtgói:

go get github.com/golang-jwt/jwt

Khi bạn đã cài đặt xong golang-jwt, hãy tạo tệp Go và nhập các gói và mô-đun này.

import (
   "log"
    "encoding/json"
   "github.com/golang-jwt/jwt"
   "net/http"
   "time"
)

Bạn sẽ sử dụng các gói này trong hướng dẫn này để ghi lỗi, thiết lập máy chủ và đặt thời gian hết hạn mã thông báo.

Thiết lập máy chủ web trong Go

Hãy bắt đầu với việc tạo một máy chủ web đơn giản với một điểm cuối sẽ được bảo mật bằng JWT.

func main() {
   http.HandleFunc("/home", handlePage)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      log.Println("There was an error listening on port :8080", err)
   }

}

Chức năng chính thiết lập điểm cuối nhà với một chức năng xử lý handlePagemà bạn sẽ thiết lập. Hàm handlePagesẽ bảo mật trang bằng JWTs. Máy chủ được thiết lập để lắng nghe trên cổng :8080, nhưng bạn có thể sử dụng bất kỳ cổng nào bạn chọn.

Hàm handlePagexử lý sẽ trả về JSON được mã hóa của Messagecấu trúc dưới dạng phản hồi cho máy khách nếu yêu cầu được ủy quyền sau khi phần thân yêu cầu được mã hóa.

type Message struct {
        Status string `json:"status"`
        Info   string `json:"info"`
}

func handlePage(writer http.ResponseWriter, request *http.Request) {
        writer.Header().Set("Content-Type", "application/json")
        var message Message
        err := json.NewDecoder(request.Body).Decode(&message)
        if err != nil {
                return
        }
        err = json.NewEncoder(writer).Encode(message)
        if err != nil {
                return
        }
}

handlePageTại thời điểm này, chức năng này chưa được xác thực và việc đưa ra các yêu cầu đối với trang sẽ hoạt động tự do . Bạn sẽ học cách thêm xác thực vào các hàm xử lý của mình ở phần sau trong hướng dẫn này.

Trang mạng API

Tạo JWT để xác thực bằng Golang-JWTgói

Bạn sẽ cần một khóa bí mật để tạo mã thông báo JWT bằng cách sử dụng golang-jwtgói. Đây là ví dụ về khóa riêng tư cho hướng dẫn này; tuy nhiên, bạn nên sử dụng một chuỗi bảo mật bằng mật mã cho khóa bí mật của mình và tải nó từ tệp biến môi trường (.env).

Hãy xem bài viết này để tìm hiểu cách sử dụng các biến môi trường trong các ứng dụng Go của bạn.

var sampleSecretKey = []byte("SecretYouShouldHide")

Vui lòng lưu ý rằng bất kỳ ai có khóa bí mật mà bạn sử dụng cho JWT của mình đều có thể xác thực người dùng ứng dụng của bạn. Biến sampleSecretKeygiữ khóa cá nhân trong trường hợp này.

Đây là một chức năng để tạo mã thông báo JWT. Hàm sẽ trả về một chuỗi và một lỗi. Nếu có lỗi khi tạo JWT, hàm sẽ trả về một chuỗi trống và lỗi. Nếu không có lỗi, hàm trả về chuỗi JWT và nilkiểu.

func generateJWT() (string, error) {

}

Bạn có thể tạo mã thông báo mới bằng Newphương pháp của gói JWT. Phương Newthức này nhận phương thức ký (thuật toán mật mã cho JWT) và trả về mã thông báo JWT.

token := jwt.New(jwt.SigningMethodEdDSA)

Nếu bạn muốn sửa đổi JWT, bạn có thể sử dụng Claimsphương thức của mã thông báo.

claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = "username"

Trong trường hợp này, bạn đang đặt thời gian hết hạn cho JWT, là mười phút, sử dụng timemô-đun, tên người dùng và trạng thái ủy quyền. Bạn sẽ có thể truy xuất các xác nhận quyền sở hữu khi cố gắng xác minh JWT.

Phần cuối cùng của việc tạo JWT là ký chuỗi bằng khóa bí mật của bạn. Bạn có thể ký chuỗi mã thông báo của mình bằng SignedStringphương pháp của mã thông báo. Phương SignedStringthức này lấy khóa bí mật và trả về một chuỗi mã thông báo đã ký.

tokenString, err := token.SignedString(sampleSecretKey)
if err != nil {
    return "", err
 }

 return tokenString, nil

Trong trường hợp có lỗi khi ký mã thông báo, bạn có thể trả về một chuỗi trống và lỗi.
Không giống như cookie, bạn không cần lưu trữ JWT; tất cả những gì bạn cần là khóa ký để xác minh mã thông báo.

Xác minh mã thông báo JWT

Phương pháp xác minh JWT thông thường sử dụng phần mềm trung gian (các hàm xử lý đảm nhận các chức năng xử lý khác cho các hoạt động). Đây là cách sử dụng phần mềm trung gian để xác minh rằng một yêu cầu được ủy quyền.

func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {

}

Hàm verifyJWTlà một phần mềm trung gian đảm nhận chức năng xử lý cho yêu cầu bạn muốn xác minh. Hàm xử lý sử dụng tham số mã thông báo từ tiêu đề yêu cầu để xác minh yêu cầu và phản hồi dựa trên trạng thái.

 return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

})

Hàm verifyJWTtrả về hàm xử lý được truyền vào dưới dạng tham số nếu yêu cầu được ủy quyền.

Bước đầu tiên để xác minh JWT là kiểm tra mã thông báo trong tiêu đề của yêu cầu.

if request.Header["Token"] != nil {

}

Nếu có mã thông báo, bạn có thể tiến hành xác minh mã thông báo và xác minh các xác nhận quyền sở hữu.

Bạn sẽ phải phân tích cú pháp mã thông báo và bạn có thể phân tích cú pháp mã thông báo bằng Parsephương pháp của jwtgói. Phương parsethức này nhận mã thông báo và một hàm trang trí JWT và trả về một giao diện và một lỗi.

Bạn cần sử dụng cùng một phương pháp ký mà bạn đã sử dụng để ký mã khi bạn tạo nó để xác minh chữ ký bằng Methodphương pháp của mã. Trong trường hợp này, phương pháp ký là phương pháp ECDSA .

token, err := jwt.Parse(request.Header\["Token"\][0], func(token *jwt.Token) (interface{}, error) {
            _, ok := token.Method.(*jwt.SigningMethodECDSA)
            if !ok {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err := writer.Write([]byte("You're Unauthorized!"))
               if err != nil {
                  return nil, err

               }
            }
            return "", nil

         })

Nếu xác minh chữ ký không thành công (hàm trả về !ok), bạn có thể trả lại StatusUnauthorizedtiêu đề cho máy khách.

if err != nil {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err2 := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
              if err2 != nil {
                      return
                }
}

Trong đoạn mã trên, có lỗi khi phân tích cú pháp mã thông báo. Do đó, người dùng không được phép, và bạn có thể viết tin nhắn và trả về trạng thái trái phép.

Bạn có thể xác thực mã thông báo bằng cách sử dụng Validphương pháp của mã thông báo.

if token.Valid {
                      endpointHandler(writer, request)
                        } else {
                                writer.WriteHeader(http.StatusUnauthorized)
                                _, err := writer.Write([]byte("You're Unauthorized due to invalid token"))
                                if err != nil {
                                        return
                                }
}

Nếu mã thông báo hợp lệ, bạn có thể chuyển vào trình xử lý điểm cuối với writerrequestcác tham số của hàm xử lý để hàm phần mềm trung gian trả về điểm cuối.

Đây là elsecâu lệnh cho trường hợp không có mã thông báo trong tiêu đề yêu cầu của khách hàng:

else {
          writer.WriteHeader(http.StatusUnauthorized)
          _, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
           if err != nil {
               return
           }
}

Vì bạn đang sử dụng phần mềm trung gian, nên hàm xử lý trong khai báo tuyến của bạn sẽ là verifyJWTphần mềm trung gian với hàm xử lý cho tuyến làm đối số.

http.HandleFunc("/home", verifyJWT(handlePage))

Khi bạn đã thêm chức năng xác minh của mình vào tuyến đường, điểm cuối sẽ được xác thực.

Xác thực điểm cuối

Về phía khách hàng, khách hàng phải cung cấp mã thông báo đã phát hành. Đây là một hàm sử dụng generateJWThàm để thêm mã thông báo trong các yêu cầu.

func authPage(writer http.ResponseWriter, ) {
        token, err := generateJWT()
        if err != nil {
                        return
        } 
        client := &http.Client{}
        request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
        request.Header.Set("Token", token)
        _, _ = client.Do(request)

}

Trong authPagehàm, tokenbiến giữ mã thông báo từ generateJWThàm. Sử dụng tham chiếu đến Clientloại httpgói, bạn có thể tạo một ứng dụng khách mới và thực hiện yêu cầu tới điểm cuối. Biến requestlà thể hiện yêu cầu và - sử dụng Setphương thức của headerphương thức của thể hiện yêu cầu - bạn có thể đặt mã thông báo trong tiêu đề yêu cầu như được hiển thị ở trên.

Bạn cũng có thể chọn đặt mã thông báo làm cookie và truy xuất nó để xác minh bất cứ khi nào khách hàng đưa ra yêu cầu đối với điểm cuối đã xác thực.

Trích xuất xác nhận quyền sở hữu từ mã thông báo JWT

Khi bạn đang tạo JWT, bạn có thể chọn nhúng thông tin vào mã thông báo. Trong generateJWThàm, bạn đã thêm usernamebiến vào claimsbản đồ.

Đây là cách bạn có thể trích xuất các xác nhận quyền sở hữu, sử dụng các usernamexác nhận quyền sở hữu làm ví dụ. Bạn có thể sử dụng phần mềm trung gian hoặc thêm chức năng vào chức năng xác minh của mình khi xác minh chữ ký mã thông báo.

func extractClaims(_ http.ResponseWriter, request *http.Request) (string, error) {
        if request.Header["Token"] != nil {
                tokenString := request.Header\["Token"\][0]
                token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

          if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
                return nil, fmt.Errorf("there's an error with the signing method")
          }
                return sampleSecretKey, nil

            })

            if err != nil {
                        return "Error Parsing Token: ", err
                }
}

Trong các extractClaimschức năng, quy trình cũng giống như verifyJWTchức năng; bạn đã truy xuất mã thông báo từ tiêu đề, phân tích cú pháp mã thông báo và xác minh chữ ký.

claims, ok := token.Claims.(jwt.MapClaims)
          if ok && token.Valid {
                username := claims["username"].(string)
                return username, nil
          }

        }
        return "unable to extract claims", nil

Khi xác thực mã thông báo, bạn có thể truy xuất xác nhận quyền sở hữu bằng Claimsphương pháp này và sử dụng bản đồ xác nhận quyền sở hữu để truy xuất dữ liệu trong JWT, như được hiển thị ở trên.

Sự kết luận

Hướng dẫn này đã dạy bạn cách sử dụng xác thực JWT để xác thực điểm cuối API và trang web của bạn trong Go với Mã thông báo web JSON bằng cách sử dụng golang-jwtgói. Bạn có thể tìm thấy mã hoàn chỉnh trong hướng dẫn này dưới dạng Github Gist .

Hãy nhớ sử dụng các biến môi trường cho khóa bí mật của bạn và không ẩn dữ liệu nhạy cảm trong JWT. Có rất nhiều hướng dẫn JWT trên blog LogRocket mà bạn có thể xem để bắt đầu với ngôn ngữ hoặc khuôn khổ mà bạn muốn sử dụng!

Nguồn: https://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

Hướng Dẫn Xác Thực JWT Trong Go
Anne  de Morel

Anne de Morel

1661094000

Un Guide Pour L'authentification JWT Dans Go

Les jetons Web JSON (JWT) sont une méthode populaire pour gérer l'authentification en ligne, et vous pouvez implémenter l'authentification JWT dans n'importe quel langage de programmation côté serveur.

Pour une lecture de base des JWT en général, je vous recommande d'en savoir plus sur les JWT, les meilleures pratiques et la sécurisation des API RESTful avec les JWT avec ces articles.

Cet article vise à vous aider à démarrer avec l'implémentation de l'authentification JWT dans vos applications Web Go à l'aide du golang-jwtpackage.

Le golang-jwt package est le package le plus populaire pour la mise en œuvre de JWT dans Go, en raison de ses fonctionnalités et de sa facilité d'utilisation. Le golang-jwtpackage fournit des fonctionnalités pour générer et valider des JWT.

Conditions préalables

Vous devrez répondre à ces exigences de base pour tirer le meilleur parti de ce didacticiel.

  • Go 1.16 ou supérieur installé sur votre machine (pour des raisons de sécurité )
  • Expérience dans la création d'applications Web en Go ou dans tout autre langage (facultatif)

Premiers pas avec le package Golang-JWT

Après avoir configuré votre espace de travail Go et initialisé le fichier de modules Go go.mod, exécutez cette commande sur votre terminal dans le répertoire de l'espace de travail pour installer le golang-jwtpackage :

go get github.com/golang-jwt/jwt

Une fois que vous avez installé le golang-jwt, créez un fichier Go et importez ces packages et modules.

import (
   "log"
    "encoding/json"
   "github.com/golang-jwt/jwt"
   "net/http"
   "time"
)

Vous utiliserez ces packages dans ce didacticiel pour consigner les erreurs, configurer un serveur et définir le délai d'expiration du jeton.

Configurer un serveur Web dans Go

Commençons par créer un serveur Web simple avec un point de terminaison qui sera sécurisé avec un JWT.

func main() {
   http.HandleFunc("/home", handlePage)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      log.Println("There was an error listening on port :8080", err)
   }

}

La fonction principale configure le point de terminaison d'accueil avec une fonction de gestionnaire handlePageque vous configurerez. La handlePagefonction sécurisera la page à l'aide de JWT. Le serveur est configuré pour écouter sur le port :8080, mais vous pouvez utiliser n'importe quel port de votre choix.

La handlePagefonction de gestionnaire renverra le JSON codé de la Messagestructure en réponse au client si la requête est autorisée après le codage du corps de la requête.

type Message struct {
        Status string `json:"status"`
        Info   string `json:"info"`
}

func handlePage(writer http.ResponseWriter, request *http.Request) {
        writer.Header().Set("Content-Type", "application/json")
        var message Message
        err := json.NewDecoder(request.Body).Decode(&message)
        if err != nil {
                return
        }
        err = json.NewEncoder(writer).Encode(message)
        if err != nil {
                return
        }
}

La handlePagefonction, à ce stade, n'est pas authentifiée et les requêtes à la page fonctionneront librement. Vous apprendrez comment ajouter une authentification à vos fonctions de gestionnaire plus loin dans ce didacticiel.

Page du réseau d'API

Génération de JWT pour l'authentification à l'aide du Golang-JWTpackage

Vous aurez besoin d'une clé secrète pour générer des jetons JWT à l'aide du golang-jwtpackage. Voici un exemple de clé privée pour ce tutoriel ; cependant, vous devez utiliser une chaîne cryptographiquement sécurisée pour votre clé secrète et la charger à partir d'un fichier de variables d'environnement (.env).

Consultez cet article pour savoir comment utiliser les variables d'environnement dans vos applications Go.

var sampleSecretKey = []byte("SecretYouShouldHide")

Veuillez noter que quiconque possède la clé secrète que vous utilisez pour vos JWT peut authentifier les utilisateurs de votre application. La sampleSecretKeyvariable contient la clé privée dans ce cas.

Voici une fonction pour générer des jetons JWT. La fonction doit renvoyer une chaîne et une erreur. S'il y a une erreur lors de la génération du JWT, la fonction renvoie une chaîne vide et l'erreur. S'il n'y a pas d'erreurs, la fonction renvoie la chaîne JWT et le niltype.

func generateJWT() (string, error) {

}

Vous pouvez créer un nouveau jeton en utilisant la Newméthode du package JWT. La Newméthode prend en charge une méthode de signature (l'algorithme cryptographique pour le JWT) et renvoie un jeton JWT.

token := jwt.New(jwt.SigningMethodEdDSA)

Si vous souhaitez modifier le JWT, vous pouvez utiliser la Claimsméthode du jeton.

claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = "username"

Dans ce cas, vous définissez un délai d'expiration pour le JWT, qui est de dix minutes, en utilisant le timemodule et le nom d'utilisateur et le statut d'autorisation. Vous pourrez récupérer les revendications lorsque vous tenterez de vérifier le JWT.

La dernière partie de la génération d'un JWT consiste à signer la chaîne à l'aide de votre clé secrète. Vous pouvez signer votre chaîne de jeton en utilisant la SignedStringméthode du jeton. La SignedStringméthode prend la clé secrète et renvoie une chaîne de jeton signée.

tokenString, err := token.SignedString(sampleSecretKey)
if err != nil {
    return "", err
 }

 return tokenString, nil

Dans les cas où il y a des erreurs lors de la signature du jeton, vous pouvez renvoyer une chaîne vide et l'erreur.
Contrairement aux cookies, vous n'avez pas besoin de stocker JWT ; tout ce dont vous avez besoin est votre clé de signature pour vérifier les jetons.

Vérification des jetons JWT

La méthode conventionnelle de vérification des JWT utilise un middleware (fonctions de gestionnaire qui prennent en charge d'autres fonctions de gestionnaire pour les opérations). Voici comment utiliser le middleware pour vérifier qu'une requête est autorisée.

func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {

}

La verifyJWTfonction est un middleware qui prend en charge la fonction de gestionnaire pour la demande que vous souhaitez vérifier. La fonction de gestionnaire utilise le paramètre de jeton de l'en-tête de la demande pour vérifier la demande et répondre en fonction de l'état.

 return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

})

La verifyJWTfonction renvoie la fonction de gestionnaire passée en paramètre si la requête est autorisée.

La première étape de la vérification des JWT consiste à inspecter le jeton dans l'en-tête de la requête.

if request.Header["Token"] != nil {

}

S'il existe un jeton, vous pouvez procéder à la vérification du jeton et vérifier les revendications.

Vous devrez analyser le jeton, et vous pouvez analyser le jeton en utilisant la Parseméthode du jwtpackage. La parseméthode prend le jeton et une fonction décoratrice JWT et renvoie une interface et une erreur.

Vous devez utiliser la même méthode de signature que celle que vous avez utilisée pour signer le jeton lorsque vous l'avez généré pour vérifier la signature à l'aide de la Methodméthode du jeton. Dans ce cas, la méthode de signature était la méthode ECDSA .

token, err := jwt.Parse(request.Header\["Token"\][0], func(token *jwt.Token) (interface{}, error) {
            _, ok := token.Method.(*jwt.SigningMethodECDSA)
            if !ok {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err := writer.Write([]byte("You're Unauthorized!"))
               if err != nil {
                  return nil, err

               }
            }
            return "", nil

         })

Si la vérification de la signature échoue (la fonction renvoie !ok), vous pouvez renvoyer un StatusUnauthorizeden-tête au client.

if err != nil {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err2 := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
              if err2 != nil {
                      return
                }
}

Dans le code ci-dessus, une erreur s'est produite lors de l'analyse du jeton. Par conséquent, l'utilisateur n'est pas autorisé et vous pouvez écrire un message et renvoyer un statut non autorisé.

Vous pouvez valider le jeton en utilisant la Validméthode du jeton.

if token.Valid {
                      endpointHandler(writer, request)
                        } else {
                                writer.WriteHeader(http.StatusUnauthorized)
                                _, err := writer.Write([]byte("You're Unauthorized due to invalid token"))
                                if err != nil {
                                        return
                                }
}

Si le jeton est valide, vous pouvez transmettre le gestionnaire de point de terminaison avec les paramètres writeret requestde la fonction de gestionnaire pour que la fonction middleware renvoie le point de terminaison.

Voici la elsedéclaration pour un cas où il n'y a pas de jeton dans l'en-tête de la requête du client :

else {
          writer.WriteHeader(http.StatusUnauthorized)
          _, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
           if err != nil {
               return
           }
}

Puisque vous utilisez un middleware, la fonction de gestionnaire dans votre déclaration de route sera le verifyJWTmiddleware avec la fonction de gestionnaire pour la route comme argument.

http.HandleFunc("/home", verifyJWT(handlePage))

Une fois que vous avez ajouté votre fonction de vérification à la route, le point de terminaison est authentifié.

Point de terminaison authentifié

Côté client, le client doit fournir un jeton émis. Voici une fonction qui utilise la generateJWTfonction pour ajouter des jetons dans les requêtes.

func authPage(writer http.ResponseWriter, ) {
        token, err := generateJWT()
        if err != nil {
                        return
        } 
        client := &http.Client{}
        request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
        request.Header.Set("Token", token)
        _, _ = client.Do(request)

}

Dans la authPagefonction, la tokenvariable contient le jeton de la generateJWTfonction. À l'aide d'une référence au Clienttype de httppackage, vous pouvez créer un nouveau client et adresser une demande au point de terminaison. La requestvariable est l'instance de la demande et, en utilisant la Setméthode de la headerméthode de l'instance de la demande, vous pouvez définir le jeton dans l'en-tête de la demande, comme indiqué ci-dessus.

Vous pouvez également choisir de définir le jeton en tant que cookie et de le récupérer pour vérification chaque fois qu'un client fait une demande au point de terminaison authentifié.

Extraction de revendications à partir de jetons JWT

Lorsque vous générez un JWT, vous pouvez choisir d'intégrer des informations dans le jeton. Dans la generateJWTfonction, vous avez ajouté la usernamevariable à la claimscarte.

Voici comment vous pouvez extraire les revendications, en utilisant les usernamerevendications comme exemple. Vous pouvez utiliser le middleware ou ajouter la fonctionnalité à votre fonction de vérification lors de la vérification de la signature du jeton.

func extractClaims(_ http.ResponseWriter, request *http.Request) (string, error) {
        if request.Header["Token"] != nil {
                tokenString := request.Header\["Token"\][0]
                token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

          if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
                return nil, fmt.Errorf("there's an error with the signing method")
          }
                return sampleSecretKey, nil

            })

            if err != nil {
                        return "Error Parsing Token: ", err
                }
}

Dans les extractClaimsfonctions, le processus est le même que la verifyJWTfonction ; vous avez extrait le jeton de l'en-tête, analysé le jeton et vérifié la signature.

claims, ok := token.Claims.(jwt.MapClaims)
          if ok && token.Valid {
                username := claims["username"].(string)
                return username, nil
          }

        }
        return "unable to extract claims", nil

Lors de la validation du jeton, vous pouvez récupérer les revendications à l'aide de la Claimsméthode et utiliser la carte des revendications pour récupérer les données dans le JWT, comme indiqué ci-dessus.

Conclusion

Ce didacticiel vous a appris à utiliser l'authentification JWT pour authentifier vos points de terminaison d'API et de page Web dans Go avec des jetons Web JSON à l'aide du golang-jwtpackage. Vous pouvez trouver le code complet dans ce tutoriel en tant que Github Gist .

N'oubliez pas d'utiliser des variables d'environnement pour vos clés secrètes et ne cachez pas de données sensibles dans les JWT. Il existe de nombreux didacticiels JWT sur le blog LogRocket que vous pouvez consulter pour vous familiariser avec le langage ou le framework qui vous intéresse !

Source : https://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

Un Guide Pour L'authentification JWT Dans Go
Saul  Alaniz

Saul Alaniz

1661091960

Una Guía Para La Autenticación JWT En Go

Los tokens web JSON (JWT) son un método popular para manejar la autenticación en línea y puede implementar la autenticación JWT en cualquier lenguaje de programación del lado del servidor.

Para la lectura de fondo de los JWT en general, recomiendo obtener más información sobre los JWT, las mejores prácticas y la protección de las API RESTful con JWT con estos artículos.

Este artículo tiene como objetivo ayudarlo a comenzar a implementar la autenticación JWT en sus aplicaciones web Go usando el golang-jwtpaquete.

El golang-jwt paquete es el paquete más popular para implementar JWT en Go, debido a sus características y facilidad de uso. El golang-jwtpaquete proporciona funcionalidad para generar y validar JWT.

requisitos previos

Deberá cumplir con estos requisitos básicos para aprovechar al máximo este tutorial.

  • Go 1.16 o posterior instalado en su máquina (por razones de seguridad )
  • Experiencia en la creación de aplicaciones web en Go o cualquier otro idioma (opcional)

Primeros pasos con el paquete Golang-JWT

Después de configurar su espacio de trabajo de Go e inicializar el archivo de módulos de Go go.mod, ejecute este comando en su terminal en el directorio del espacio de trabajo para instalar el golang-jwtpaquete:

go get github.com/golang-jwt/jwt

Una vez que haya instalado el golang-jwt, cree un archivo Go e importe estos paquetes y módulos.

import (
   "log"
    "encoding/json"
   "github.com/golang-jwt/jwt"
   "net/http"
   "time"
)

Utilizará estos paquetes en este tutorial para registrar errores, configurar un servidor y establecer el tiempo de vencimiento del token.

Configuración de un servidor web en Go

Comencemos con la creación de un servidor web simple con un punto final que se protegerá con un JWT.

func main() {
   http.HandleFunc("/home", handlePage)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      log.Println("There was an error listening on port :8080", err)
   }

}

La función principal configura el punto final de inicio con una función de controlador handlePageque usted configurará. La handlePagefunción asegurará la página usando JWT. El servidor está configurado para escuchar en el puerto :8080, pero puede usar cualquier puerto de su elección.

La handlePagefunción del controlador devolverá el JSON codificado de la Messageestructura como respuesta al cliente si la solicitud se autoriza después de codificar el cuerpo de la solicitud.

type Message struct {
        Status string `json:"status"`
        Info   string `json:"info"`
}

func handlePage(writer http.ResponseWriter, request *http.Request) {
        writer.Header().Set("Content-Type", "application/json")
        var message Message
        err := json.NewDecoder(request.Body).Decode(&message)
        if err != nil {
                return
        }
        err = json.NewEncoder(writer).Encode(message)
        if err != nil {
                return
        }
}

La handlePagefunción, en este punto, no está autenticada y realizar solicitudes a la página funcionará libremente. Aprenderá cómo agregar autenticación a sus funciones de controlador más adelante en este tutorial.

página de la red API

Generación de JWT para autenticación usando el Golang-JWTpaquete

Necesitará una clave secreta para generar tokens JWT utilizando el golang-jwtpaquete. Aquí hay un ejemplo de clave privada para este tutorial; sin embargo, debe usar una cadena criptográficamente segura para su clave secreta y cargarla desde un archivo de variables de entorno (.env).

Consulte este artículo para aprender a usar variables de entorno en sus aplicaciones Go.

var sampleSecretKey = []byte("SecretYouShouldHide")

Tenga en cuenta que quien tenga la clave secreta que usa para sus JWT puede autenticar a los usuarios de su aplicación. La sampleSecretKeyvariable contiene la clave privada en este caso.

Aquí hay una función para generar tokens JWT. La función debe devolver una cadena y un error. Si hay un error al generar el JWT, la función devuelve una cadena vacía y el error. Si no hay errores, la función devuelve la cadena JWT y el niltipo.

func generateJWT() (string, error) {

}

Puede crear un nuevo token utilizando el Newmétodo del paquete JWT. El Newmétodo toma un método de firma (el algoritmo criptográfico para JWT) y devuelve un token JWT.

token := jwt.New(jwt.SigningMethodEdDSA)

Si desea modificar el JWT, puede usar el Claimsmétodo del token.

claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = "username"

En este caso, está configurando un tiempo de caducidad para el JWT, que es de diez minutos, utilizando el timemódulo y el nombre de usuario y el estado de autorización. Podrá recuperar los reclamos cuando intente verificar el JWT.

La parte final de generar un JWT es firmar la cadena con su clave secreta. Puede firmar su cadena de token usando el SignedStringmétodo del token. El SignedStringmétodo toma la clave secreta y devuelve una cadena de token firmada.

tokenString, err := token.SignedString(sampleSecretKey)
if err != nil {
    return "", err
 }

 return tokenString, nil

En los casos en que haya errores al firmar el token, puede devolver una cadena vacía y el error.
A diferencia de las cookies, no necesita almacenar JWT; todo lo que necesita es su clave de firma para verificar los tokens.

Verificación de tokens JWT

El método convencional de verificación de JWT utiliza middleware (funciones de controlador que toman otras funciones de controlador para las operaciones). Aquí se explica cómo usar el middleware para verificar que una solicitud está autorizada.

func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {

}

La verifyJWTfunción es un middleware que acepta la función de controlador para la solicitud que desea verificar. La función del controlador usa el parámetro token del encabezado de la solicitud para verificar la solicitud y responder según el estado.

 return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

})

La verifyJWTfunción devuelve la función de controlador pasada como parámetro si la solicitud está autorizada.

El primer paso para verificar los JWT es inspeccionar el token en el encabezado de la solicitud.

if request.Header["Token"] != nil {

}

Si hay un token, puede proceder a verificar el token y verificar las reclamaciones.

Tendrá que analizar el token y puede analizar el token utilizando el Parsemétodo del jwtpaquete. El parsemétodo toma el token y una función de decorador JWT y devuelve una interfaz y un error.

Debe usar el mismo método de firma que usó para firmar el token cuando lo generó para verificar la firma usando el Methodmétodo del token. En este caso, el método de firma fue el método ECDSA .

token, err := jwt.Parse(request.Header\["Token"\][0], func(token *jwt.Token) (interface{}, error) {
            _, ok := token.Method.(*jwt.SigningMethodECDSA)
            if !ok {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err := writer.Write([]byte("You're Unauthorized!"))
               if err != nil {
                  return nil, err

               }
            }
            return "", nil

         })

Si la verificación de la firma falla (la función devuelve !ok), puede devolver un StatusUnauthorizedencabezado al cliente.

if err != nil {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err2 := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
              if err2 != nil {
                      return
                }
}

En el código anterior, hay un error al analizar el token. Por lo tanto, el usuario no está autorizado y puede escribir un mensaje y devolver un estado no autorizado.

Puede validar el token utilizando el Validmétodo del token.

if token.Valid {
                      endpointHandler(writer, request)
                        } else {
                                writer.WriteHeader(http.StatusUnauthorized)
                                _, err := writer.Write([]byte("You're Unauthorized due to invalid token"))
                                if err != nil {
                                        return
                                }
}

Si el token es válido, puede pasar el controlador de punto final con los parámetros writery requestde la función del controlador para que la función de middleware devuelva el punto final.

Aquí está la elsedeclaración para un caso en el que no hay token en el encabezado de la solicitud del cliente:

else {
          writer.WriteHeader(http.StatusUnauthorized)
          _, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
           if err != nil {
               return
           }
}

Dado que está utilizando middleware, la función de controlador en su declaración de ruta será el verifyJWTmiddleware con la función de controlador para la ruta como argumento.

http.HandleFunc("/home", verifyJWT(handlePage))

Una vez que haya agregado su función de verificación a la ruta, el punto final se autentica.

Endpoint autenticado

En el lado del cliente, el cliente debe proporcionar un token emitido. Aquí hay una función que usa la generateJWTfunción para agregar tokens en las solicitudes.

func authPage(writer http.ResponseWriter, ) {
        token, err := generateJWT()
        if err != nil {
                        return
        } 
        client := &http.Client{}
        request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
        request.Header.Set("Token", token)
        _, _ = client.Do(request)

}

En la authPagefunción, la tokenvariable contiene el token de la generateJWTfunción. Usando una referencia al Clienttipo de httppaquete, puede crear un nuevo cliente y realizar una solicitud al punto final. La requestvariable es la instancia de la solicitud y, utilizando el Setmétodo del headermétodo de la instancia de la solicitud, puede configurar el token en el encabezado de la solicitud como se muestra arriba.

También puede optar por configurar el token como una cookie y recuperarlo para su verificación cada vez que un cliente realice una solicitud al punto final autenticado.

Extracción de reclamos de tokens JWT

Cuando genera un JWT, puede elegir incrustar información en el token. En la generateJWTfunción, agregó la usernamevariable al claimsmapa.

Así es como puede extraer los reclamos, usando los usernamereclamos como ejemplo. Puede usar middleware o agregar la funcionalidad a su función de verificación al verificar la firma del token.

func extractClaims(_ http.ResponseWriter, request *http.Request) (string, error) {
        if request.Header["Token"] != nil {
                tokenString := request.Header\["Token"\][0]
                token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

          if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
                return nil, fmt.Errorf("there's an error with the signing method")
          }
                return sampleSecretKey, nil

            })

            if err != nil {
                        return "Error Parsing Token: ", err
                }
}

En las extractClaimsfunciones, el proceso es el mismo que la verifyJWTfunción; recuperó el token del encabezado, analizó el token y verificó la firma.

claims, ok := token.Claims.(jwt.MapClaims)
          if ok && token.Valid {
                username := claims["username"].(string)
                return username, nil
          }

        }
        return "unable to extract claims", nil

Al validar el token, puede recuperar los reclamos usando el Claimsmétodo y usar el mapa de reclamos para recuperar los datos en el JWT, como se muestra arriba.

Conclusión

Este tutorial le enseñó cómo usar la autenticación JWT para autenticar su API y los puntos finales de la página web en Go con JSON Web Tokens mediante el uso del golang-jwtpaquete. Puede encontrar el código completo en este tutorial como Github Gist .

Recuerde usar variables de entorno para sus claves secretas y no oculte datos confidenciales en JWT. ¡Hay muchos tutoriales de JWT en el blog de LogRocket que puede consultar para comenzar a usar el lenguaje o el marco que le interesa usar!

Fuente: https://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

Una Guía Para La Autenticación JWT En Go
Iara  Simões

Iara Simões

1661091660

Um Guia Para Autenticação JWT Em Go

Os JSON Web Tokens (JWTs) são um método popular para lidar com autenticação online e você pode implementar a autenticação JWT em qualquer linguagem de programação do lado do servidor.

Para a leitura em segundo plano de JWTs em geral, recomendo aprender mais sobre JWTs, práticas recomendadas e segurança de APIs RESTful com JWTs com estes artigos.

Este artigo tem como objetivo ajudá-lo a começar a implementar a autenticação JWT em seus aplicativos Web Go usando o golang-jwtpacote.

O golang-jwt pacote é o pacote mais popular para implementação de JWTs em Go, devido aos seus recursos e facilidade de uso. O golang-jwtpacote fornece funcionalidade para gerar e validar JWTs.

Pré-requisitos

Você precisará atender a esses requisitos básicos para aproveitar ao máximo este tutorial.

  • Go 1.16 ou posterior instalado em sua máquina (por motivos de segurança )
  • Experiência na criação de aplicativos da Web em Go ou em qualquer outro idioma (opcional)

Introdução ao pacote Golang-JWT

Depois de configurar seu espaço de trabalho Go e inicializar o arquivo de módulos Go go.mod, execute este comando em seu terminal no diretório do espaço de trabalho para instalar o golang-jwtpacote:

go get github.com/golang-jwt/jwt

Depois de instalar o golang-jwt, crie um arquivo Go e importe esses pacotes e módulos.

import (
   "log"
    "encoding/json"
   "github.com/golang-jwt/jwt"
   "net/http"
   "time"
)

Você usará esses pacotes neste tutorial para registrar erros, configurar um servidor e definir o tempo de expiração do token.

Configurando um servidor web em Go

Vamos começar criando um servidor web simples com um endpoint que será protegido com um JWT.

func main() {
   http.HandleFunc("/home", handlePage)
   err := http.ListenAndServe(":8080", nil)
   if err != nil {
      log.Println("There was an error listening on port :8080", err)
   }

}

A função main configura o endpoint inicial com uma função de manipulador handlePageque você configurará. A handlePagefunção protegerá a página usando JWTs. O servidor está configurado para escutar na porta :8080, mas você pode usar qualquer porta de sua escolha.

A handlePagefunção do manipulador retornará o JSON codificado da Messageestrutura como uma resposta ao cliente se a solicitação for autorizada após a codificação do corpo da solicitação.

type Message struct {
        Status string `json:"status"`
        Info   string `json:"info"`
}

func handlePage(writer http.ResponseWriter, request *http.Request) {
        writer.Header().Set("Content-Type", "application/json")
        var message Message
        err := json.NewDecoder(request.Body).Decode(&message)
        if err != nil {
                return
        }
        err = json.NewEncoder(writer).Encode(message)
        if err != nil {
                return
        }
}

A handlePagefunção, neste momento, não está autenticada e fazer solicitações à página funcionará livremente. Você aprenderá como adicionar autenticação às funções do manipulador posteriormente neste tutorial.

página de rede da API

Gerando JWTs para autenticação usando o Golang-JWTpacote

Você precisará de uma chave secreta para gerar tokens JWT usando o golang-jwtpacote. Aqui está um exemplo de chave privada para este tutorial; entretanto, você deve usar uma string criptograficamente segura para sua chave secreta e carregá-la de um arquivo de variáveis ​​de ambiente (.env).

Confira este artigo para saber como usar variáveis ​​de ambiente em seus aplicativos Go.

var sampleSecretKey = []byte("SecretYouShouldHide")

Observe que quem tiver a chave secreta que você usa para seus JWTs pode autenticar os usuários do seu aplicativo. A sampleSecretKeyvariável contém a chave privada neste caso.

Aqui está uma função para gerar tokens JWT. A função deve retornar uma string e um erro. Se houver um erro ao gerar o JWT, a função retornará uma string vazia e o erro. Se não houver erros, a função retornará a string JWT e o niltipo.

func generateJWT() (string, error) {

}

Você pode criar um novo token usando o Newmétodo do pacote JWT. O Newmétodo recebe um método de assinatura (o algoritmo criptográfico para o JWT) e retorna um token JWT.

token := jwt.New(jwt.SigningMethodEdDSA)

Se você deseja modificar o JWT, pode usar o Claimsmétodo do token.

claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = "username"

Nesse caso, você está definindo um tempo de expiração para o JWT, que é de dez minutos, usando o timemódulo e o nome de usuário e o status de autorização. Você poderá recuperar as declarações ao tentar verificar o JWT.

A parte final da geração de um JWT é assinar a string usando sua chave secreta. Você pode assinar sua string de token usando o SignedStringmétodo do token. O SignedStringmétodo pega a chave secreta e retorna uma string de token assinada.

tokenString, err := token.SignedString(sampleSecretKey)
if err != nil {
    return "", err
 }

 return tokenString, nil

Nos casos em que houver erros ao assinar o token, você poderá retornar uma string vazia e o erro.
Ao contrário dos cookies, você não precisa armazenar JWT; tudo que você precisa é sua chave de assinatura para verificar os tokens.

Verificando tokens JWT

O método convencional de verificação de JWTs usa middleware (funções de manipulador que recebem outras funções de manipulador para operações). Veja como usar o middleware para verificar se uma solicitação foi autorizada.

func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {

}

A verifyJWTfunção é um middleware que recebe a função do manipulador para a solicitação que você deseja verificar. A função do manipulador usa o parâmetro token do cabeçalho da solicitação para verificar a solicitação e responder com base no status.

 return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

})

A verifyJWTfunção retorna a função do manipulador passada como parâmetro se a solicitação for autorizada.

A primeira etapa para verificar os JWTs é inspecionar o token no cabeçalho da solicitação.

if request.Header["Token"] != nil {

}

Se houver um token, você poderá verificar o token e verificar as declarações.

Você terá que analisar o token e poderá analisar o token usando o Parsemétodo do jwtpacote. O parsemétodo recebe o token e uma função de decorador JWT e retorna uma interface e um erro.

Você precisa usar o mesmo método de assinatura usado para assinar o token quando o gerou para verificar a assinatura usando o Methodmétodo do token. Nesse caso, o método de assinatura foi o método ECDSA .

token, err := jwt.Parse(request.Header\["Token"\][0], func(token *jwt.Token) (interface{}, error) {
            _, ok := token.Method.(*jwt.SigningMethodECDSA)
            if !ok {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err := writer.Write([]byte("You're Unauthorized!"))
               if err != nil {
                  return nil, err

               }
            }
            return "", nil

         })

Se a verificação da assinatura falhar (a função retorna !ok), você pode retornar um StatusUnauthorizedcabeçalho para o cliente.

if err != nil {
               writer.WriteHeader(http.StatusUnauthorized)
               _, err2 := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
              if err2 != nil {
                      return
                }
}

No código acima, há um erro ao analisar o token. Portanto, o usuário não está autorizado e você pode escrever uma mensagem e retornar um status não autorizado.

Você pode validar o token usando o Validmétodo do token.

if token.Valid {
                      endpointHandler(writer, request)
                        } else {
                                writer.WriteHeader(http.StatusUnauthorized)
                                _, err := writer.Write([]byte("You're Unauthorized due to invalid token"))
                                if err != nil {
                                        return
                                }
}

Se o token for válido, você poderá passar o manipulador de terminal com os parâmetros writere requestda função do manipulador para que a função de middleware retorne o terminal.

Aqui está a elseinstrução para um caso em que não há token no cabeçalho da solicitação do cliente:

else {
          writer.WriteHeader(http.StatusUnauthorized)
          _, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
           if err != nil {
               return
           }
}

Já que você está usando middleware, a função handler em sua declaração de rota será o verifyJWTmiddleware com a função handler para a rota como argumento.

http.HandleFunc("/home", verifyJWT(handlePage))

Depois de adicionar sua função de verificação à rota, o endpoint é autenticado.

Endpoint autenticado

No lado do cliente, o cliente deve fornecer um token emitido. Aqui está uma função que usa a generateJWTfunção para adicionar tokens em solicitações.

func authPage(writer http.ResponseWriter, ) {
        token, err := generateJWT()
        if err != nil {
                        return
        } 
        client := &http.Client{}
        request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
        request.Header.Set("Token", token)
        _, _ = client.Do(request)

}

Na authPagefunção, a tokenvariável contém o token da generateJWTfunção. Usando uma referência ao Clienttipo do httppacote, você pode criar um novo cliente e fazer uma solicitação ao endpoint. A requestvariável é a instância da solicitação e — usando o Setmétodo do headermétodo da instância da solicitação — você pode definir o token no cabeçalho da solicitação conforme mostrado acima.

Você também pode optar por definir o token como um cookie e recuperá-lo para verificação sempre que um cliente fizer uma solicitação ao endpoint autenticado.

Extraindo declarações de tokens JWT

Ao gerar um JWT, você pode optar por incorporar informações no token. Na generateJWTfunção, você adicionou a usernamevariável ao claimsmapa.

Veja como você pode extrair as declarações, usando as usernamedeclarações como exemplo. Você pode usar middleware ou adicionar a funcionalidade à sua função de verificação ao verificar a assinatura do token.

func extractClaims(_ http.ResponseWriter, request *http.Request) (string, error) {
        if request.Header["Token"] != nil {
                tokenString := request.Header\["Token"\][0]
                token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

          if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
                return nil, fmt.Errorf("there's an error with the signing method")
          }
                return sampleSecretKey, nil

            })

            if err != nil {
                        return "Error Parsing Token: ", err
                }
}

Nas extractClaimsfunções, o processo é o mesmo que a verifyJWTfunção; você recuperou o token do cabeçalho, analisou o token e verificou a assinatura.

claims, ok := token.Claims.(jwt.MapClaims)
          if ok && token.Valid {
                username := claims["username"].(string)
                return username, nil
          }

        }
        return "unable to extract claims", nil

Ao validar o token, você pode recuperar as declarações usando o Claimsmétodo e usar o mapa de declarações para recuperar os dados no JWT, conforme mostrado acima.

Conclusão

Este tutorial ensinou como usar a autenticação JWT para autenticar seus endpoints de API e página da Web em Go com JSON Web Tokens usando o golang-jwtpacote. Você pode encontrar o código completo neste tutorial como um Github Gist .

Lembre-se de usar variáveis ​​de ambiente para suas chaves secretas e não oculte dados confidenciais em JWTs. Existem muitos tutoriais de JWT no blog da LogRocket que você pode conferir para começar a usar a linguagem ou estrutura que você está interessado em usar!

Fonte: https://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

Um Guia Para Autenticação JWT Em Go

A Guide to JWT Authentication in Go

JSON Web Tokens (JWTs) are a popular method for dealing with online authentication, and you can implement JWT authentication in any server-side programming language.

For background reading JWTs in general, I recommend learning more about JWTs, best practices, and securing RESTful APIs with JWTs with these articles.

This article is aimed at helping you get started with implementing JWT authentication in your Go web applications using the golang-jwt package.

The golang-jwt package is the most popular package for implementing JWTs in Go, owing to its features and ease of use. The golang-jwt package provides functionality for generating and validating JWTs.

See more at: https://blog.logrocket.com/jwt-authentication-go/

#go #jwt 

A Guide to JWT Authentication in Go
井上  康弘

井上 康弘

1660921469

Laravel 9 中 JWT 身份驗證的完整指南

Laravel中設置基於 JWT 令牌的身份驗證很容易。與網站交互的傳統過程是從登錄頁面登錄。接下來,您執行所需的操作,然後註銷。但是,在REST API的情況下,過程完全不同。 JWT(JSON Web Token)通常用於發送可以使用數字簽名進行信任和驗證的信息。

我們什麼時候可以使用 JSON Web Tokens

讓我們說; 您有一個需要與服務器通信的移動應用程序。現在,服務器需要識別他們正在與誰交談。但不幸的是,HTTP 是一種無狀態協議。所以我們需要創建一種機制來解決我們的問題:服務器將如何識別用戶是新用戶還是舊用戶。它是否已經在應用程序中註冊。它是否授權用戶?在這種情況下,我們可以使用JWT Authentication

Laravel JWT 身份驗證

  1. 用戶向服務器發送註冊發布請求,服務器在該數據庫上創建用戶和 JWT 令牌並返回JWT 令牌 作為響應。
  2. JWT 存儲在瀏覽器的本地或其他存儲機制中。
  3. 當用戶發出另一個請求時,它需要在請求標頭中附加該令牌。
  4. 服務器檢查該令牌,並根據 JWT 令牌是否有效,返迴響應。
  5. 在用戶註銷應用程序並從本地存儲中銷毀該令牌之前,它始終會檢查它。如果令牌有效,則它可以訪問特定資源。
  6. 如果令牌被破壞或被操縱,用戶將重定向到登錄屏幕,他需要填寫用戶名和密碼。
  7. 如果用戶名和密碼有效,則作為響應,它會將JWT 令牌發送回用戶。然後,同樣的過程,用戶將其存儲在本地存儲中,並為每個請求發送該令牌,以向服務器驗證他有一個受信任的用戶並且可以訪問特定資源。

像往常一樣,我們通過安裝新的Laravel 來啟動這個項目。

 第 1 步:安裝和配置 Laravel

通過以下命令安裝 Laravel。

 

composer create-project laravel/laravel jwtauth --prefer-dist

配置數據庫。

現在,通過鍵入以下命令安裝第三方jwtauth包。

 

composer require tymon/jwt-auth

它將在 vendor 文件夾中安裝包,並且我們的composer.json 文件將被更新。

第 2 步:更新 JWT 包的 config/app.php

轉到 config >> app.php 文件並添加以下內容。

'providers' => [
    ....
    'Tymon\JWTAuth\Providers\JWTAuthServiceProvider',
],
'aliases' => [
    ....
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
        'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],

要在 Laravel 中發布配置文件,您需要運行以下代碼行:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

現在對於令牌加密,我需要通過運行以下代碼行來生成一個密鑰:

php artisan jwt:generate

如果您在點擊上述命令後發現這樣的錯誤。

ReflectionException:方法 Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() 不存在

您需要執行以下步驟。

轉到 位於 vendor/tymon/src/Commands中的JWTGenerateCommand.php文件並粘貼這部分代碼。public function handle() { $this->fire(); }

您可以了解有關此問題的更多信息。

第三步:將用戶註冊到數據庫中。

通過以下命令將表遷移到數據庫中。

php artisan migrate

現在,為用戶註冊和身份驗證創建兩個控制器文件。

  1. APIRegisterController.php
  2. APILoginController.php

請鍵入以下命令來生成它。

php artisan make:controller APIRegisterController
php artisan make:controller APILoginController

另外,在routes >> api.php 文件中註冊 api 路由 。

Route::post('user/register', 'APIRegisterController@register');
Route::post('user/login', 'APILoginController@login');

首先,我們 在APIRegisterController.php 文件中編寫註冊函數 。

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use JWTFactory;
use JWTAuth;
use Validator;
use Response;

class APIRegisterController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255|unique:users',
            'name' => 'required',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        User::create([
            'name' => $request->get('name'),
            'email' => $request->get('email'),
            'password' => bcrypt($request->get('password')),
        ]);
        $user = User::first();
        $token = JWTAuth::fromUser($user);
        
        return Response::json(compact('token'));
    }
}

我所做的是首先檢查驗證,然後如果所有表單數據看起來都正確,它將在數據庫中註冊用戶並返回一個 JWT 令牌。我們正在基於 User 對像生成令牌。您可以根據需要創建令牌。您可以在此處找到更多指導。

第 4 步:在 Postman 中測試。

我們正在通過郵遞員註冊用戶。所以讓我們這樣做。

首先,我們檢查驗證。

Laravel API 認證教程

 

現在,填寫您的姓名、電子郵件和 密碼 ,看看我們是否可以獲得令牌。

 

Laravel 5.6 JWT 認證教程

哎呀!!我們已經成功註冊了用戶並取回了 JWT 令牌。現在將此令牌保存在本地存儲中,當我們需要訪問任何受保護的資源時,將此令牌作為 Auth Bearer 傳遞以獲取請求並獲取該路由。

第五步:登錄用戶。

我們已經 在api.php 文件中定義了登錄 路由 。現在,轉到APILoginController.php 文件並編寫 登錄 函數的代碼。

// APILoginController.php

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
use JWTFactory;
use JWTAuth;
use App\User;
use Illuminate\Support\Facades\Auth;

class APILoginController extends Controller
{
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        $credentials = $request->only('email', 'password');
        try {
            if (! $token = JWTAuth::attempt($credentials)) {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        } catch (JWTException $e) {
            return response()->json(['error' => 'could_not_create_token'], 500);
        }
        return response()->json(compact('token'));
    }
}

如果郵箱和密碼正確,我們就可以生成 JWT 令牌。否則,我們會得到一個錯誤。現在在POSTMAN中檢查這個,看看我們是否可以獲得令牌。

 

Laravel 5.6 API 認證教程

第 6 步:包括中間件以保護資源。

tymondesigns / jwt-auth 包 默認為我們提供了兩個中間件。

  • jwt.auth

jwt.刷新

我們需要將這些中間件註冊到app >> Http >> Kernel.php 文件中。

protected $routeMiddleware = [
...
...
'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
]

定義一個需要通過JWT Token Authentication保護的路由。

// api.php

Route::middleware('jwt.auth')->get('users', function(Request $request) {
    return auth()->user();
});

現在,登錄到應用程序並獲取令牌。我們可以在 get 請求中使用這個令牌,如下所示。

Authorization: Bearer {yourtokenhere}

 

而且,我們正在讓用戶回來。所以我們功能齊全的 Laravel JWT 身份驗證教程示例 正在運行。所以,我把這段代碼放在了 Github 上。所以也請檢查一下。

鏈接:https ://appdividend.com/2022/02/28/laravel-jwt-authentication/

#laravel #jwt

Laravel 9 中 JWT 身份驗證的完整指南
Hans  Marvin

Hans Marvin

1660914240

The Complete Guide to JWT Authentication in Laravel 9

Setting up JWT Token-based Authentication in Laravel is easy. The traditional process of interacting with a website is logging in from the login page. Next, you perform your desired actions and then log out. However, in the case of REST API, the process is entirely different. JWT (JSON Web Token) is usually used to send information that can be trusted and verified using a digital signature.

When we can use JSON Web Tokens

Let us say; you have a mobile application that needs to communicate with the server. Now, a server needs to identify with whom they are talking. But unfortunately, HTTP is a stateless protocol. So we need to create a mechanism that resolves our issue: how the server will identify that the user is new or old. Is it already registered with the application or not. Is it authorized a user or not? In that scenario, we can use JWT Authentication.

Laravel JWT Authentication

  1. A user sends a signup post request to the server, and the server creates a user and JWT token on that database and returns a JWT token as a response.
  2. JWT  is stored either in the browser’s local or other storage mechanisms.
  3. When a user makes another request, it needs to append that token in the request header.
  4. The server checked that token, and based on whether the JWT token was valid or not, it returned a response.
  5. Until a user logs out of the application and destroys that token from the local storage, it always checks for it. If the token is valid, then it can access the particular resources.
  6. If the token is destroyed or manipulated, the user redirects to the login screen, and he needs to fill in the username and password.
  7. If the username and password are valid, then in response, it sends a JWT token back to the user. Then, again same procedure, the user stores it in local storage and sends that token for every request to verify with the server that he has a trusted user and can access the particular resources.

See more at: https://appdividend.com/2022/02/28/laravel-jwt-authentication/

#laravel #jwt

The Complete Guide to JWT Authentication in Laravel 9
Thierry  Perret

Thierry Perret

1660906980

Le Guide Complet De L'authentification JWT Dans Laravel 9

La configuration de l' authentification basée sur les jetons JWT dans Laravel est simple. Le processus traditionnel d'interaction avec un site Web consiste à se connecter à partir de la page de connexion. Ensuite, vous effectuez les actions souhaitées, puis vous vous déconnectez. Cependant, dans le cas de l' API REST , le processus est entièrement différent. JWT (JSON Web Token) est généralement utilisé pour envoyer des informations fiables et vérifiées à l'aide d'une signature numérique.

Quand pouvons-nous utiliser les jetons Web JSON

Laisse nous dire; vous avez une application mobile qui doit communiquer avec le serveur. Maintenant, un serveur doit identifier avec qui il parle. Mais malheureusement, HTTP est un protocole sans état. Nous devons donc créer un mécanisme qui résout notre problème : comment le serveur identifiera que l'utilisateur est nouveau ou ancien. Est-il déjà enregistré avec l'application ou non. Est-ce un utilisateur autorisé ou non ? Dans ce scénario, nous pouvons utiliser JWT Authentication .

Authentification Laravel JWT

  1. Un utilisateur envoie une demande de publication d'inscription au serveur, et le serveur crée un utilisateur et un jeton JWT sur cette base de données et renvoie un jeton JWT  en réponse.
  2. JWT  est stocké dans les mécanismes de stockage locaux ou autres du navigateur.
  3. Lorsqu'un utilisateur fait une autre demande, il doit ajouter ce jeton dans l'en-tête de la demande.
  4. Le serveur a vérifié ce jeton et, selon que le jeton JWT était valide ou non, il a renvoyé une réponse.
  5. Jusqu'à ce qu'un utilisateur se déconnecte de l'application et détruise ce jeton du stockage local, il le vérifie toujours. Si le jeton est valide, il peut accéder aux ressources particulières.
  6. Si le jeton est détruit ou manipulé, l'utilisateur est redirigé vers l'écran de connexion, et il doit renseigner le nom d'utilisateur et le mot de passe.
  7. Si le nom d'utilisateur et le mot de passe sont valides, en réponse, il renvoie un jeton JWT à l'utilisateur. Ensuite, toujours selon la même procédure, l'utilisateur le stocke dans le stockage local et envoie ce jeton pour chaque demande afin de vérifier auprès du serveur qu'il a un utilisateur de confiance et qu'il peut accéder aux ressources particulières.

Comme d'habitude, nous commençons ce projet en installant un nouveau Laravel.

 Étape 1 : Installer et configurer Laravel

Installez Laravel avec la commande suivante.

 

composer create-project laravel/laravel jwtauth --prefer-dist

Configurez la base de données.

Maintenant, installez le package tiers jwtauth en tapant la commande suivante.

 

composer require tymon/jwt-auth

Il installera le package dans le  dossier du fournisseur  et notre fichier composer.json  sera mis à jour.

Étape 2 : Mettez à jour le fichier config/app.php pour le package JWT

Accédez au  fichier config >> app.php  et ajoutez ce qui suit.

'providers' => [
    ....
    'Tymon\JWTAuth\Providers\JWTAuthServiceProvider',
],
'aliases' => [
    ....
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
        'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],

Pour publier le fichier de configuration dans Laravel, vous devez exécuter la ligne de code suivante :

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

Maintenant, pour le chiffrement des jetons, je dois générer une clé secrète en exécutant la ligne de code suivante :

php artisan jwt:generate

Si vous trouvez une erreur comme celle-ci après avoir appuyé sur la commande ci-dessus.

ReflectionException : la méthode Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() n'existe pas

Vous devez effectuer l'étape suivante.

Accédez au fichier JWTGenerateCommand.php  situé dans  vendor/tymon/src/Commands et collez cette partie du code.public function handle() { $this->fire(); }

Vous pouvez en savoir plus sur ce problème .

Étape 3 : Enregistrez l'utilisateur dans la base de données.

Migrez les tables dans la base de données à l'aide de la commande suivante.

php artisan migrate

Maintenant, créez deux fichiers de contrôleur pour l'enregistrement et l'authentification des utilisateurs.

  1. APIRegisterController.php
  2. APILoginController.php

Veuillez taper la commande suivante pour le générer.

php artisan make:controller APIRegisterController
php artisan make:controller APILoginController

Enregistrez également les routes API dans les  routes >> fichier api.php  .

Route::post('user/register', 'APIRegisterController@register');
Route::post('user/login', 'APILoginController@login');

Tout d'abord, nous  codons la fonction de registre  dans le fichier APIRegisterController.php  .

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use JWTFactory;
use JWTAuth;
use Validator;
use Response;

class APIRegisterController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255|unique:users',
            'name' => 'required',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        User::create([
            'name' => $request->get('name'),
            'email' => $request->get('email'),
            'password' => bcrypt($request->get('password')),
        ]);
        $user = User::first();
        $token = JWTAuth::fromUser($user);
        
        return Response::json(compact('token'));
    }
}

Ce que j'ai fait, c'est d'abord vérifier la validation, puis si toutes les données du formulaire semblent correctes, il enregistrera l'utilisateur dans la base de données et renverra un jeton JWT. Nous générons le jeton en fonction de l'objet User. Vous pouvez créer le jeton à partir de tout ce que vous voulez. Vous pouvez trouver plus de conseils ici .

Étape 4 : Testez dans Postman.

Nous enregistrons l'utilisateur via le facteur. Alors faisons cela.

Tout d'abord, nous vérifions la validation.

Tutoriel d'authentification de l'API Laravel

 

Maintenant, remplissez votre nom, votre adresse e-mail et  votre mot de passe  et voyez si nous pouvons obtenir le jeton ou non.

 

Tutoriel d'authentification Laravel 5.6 JWT

Aïe !! Nous avons réussi à enregistrer l'utilisateur et à récupérer le jeton JWT. Enregistrez maintenant ce jeton dans le stockage local et, lorsque nous devons accéder à une ressource protégée, transmettez ce jeton en tant que porteur d'authentification pour obtenir une requête et obtenir cette route.

Étape 5 : Connectez-vous à l'utilisateur.

Nous avons déjà défini la  route de connexion  dans le  fichier api.php  . Maintenant, allez dans le fichier  APILoginController.php  et codez la fonction de connexion  .

// APILoginController.php

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
use JWTFactory;
use JWTAuth;
use App\User;
use Illuminate\Support\Facades\Auth;

class APILoginController extends Controller
{
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        $credentials = $request->only('email', 'password');
        try {
            if (! $token = JWTAuth::attempt($credentials)) {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        } catch (JWTException $e) {
            return response()->json(['error' => 'could_not_create_token'], 500);
        }
        return response()->json(compact('token'));
    }
}

Si l'e-mail et le mot de passe sont corrects, nous pouvons générer le jeton JWT. Sinon, nous obtenons une erreur. Maintenant, vérifiez cela dans le POSTMAN et voyez si nous pouvons obtenir le jeton.

 

Tutoriel d'authentification de l'API Laravel 5.6

Étape 6 : incluez le middleware pour protéger les ressources.

Le  package  tymondesigns / jwt-auth nous fournit, par défaut, deux middlewares.

  • jwt.auth

jwt.refresh

Nous devons enregistrer ces middlewares dans l' application >> Http >>  fichier Kernel.php.

protected $routeMiddleware = [
...
...
'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
]

Définissez une route qui doit être protégée via JWT Token Authentication .

// api.php

Route::middleware('jwt.auth')->get('users', function(Request $request) {
    return auth()->user();
});

Maintenant, connectez-vous à l'application et obtenez le jeton. Nous pouvons utiliser ce jeton dans la requête get comme suit.

Authorization: Bearer {yourtokenhere}

 

Et, nous récupérons l'utilisateur. Donc, notre  exemple de didacticiel d'authentification Laravel JWT  entièrement fonctionnel fonctionne. J'ai donc mis ce code sur Github. Veuillez donc vérifier cela également.

Lien : https://appdividend.com/2022/02/28/laravel-jwt-authentication/

#laravel #jwt

Le Guide Complet De L'authentification JWT Dans Laravel 9
Minh  Nguyet

Minh Nguyet

1660899720

Hướng Dẫn Hoàn Chỉnh Về Xác Thực JWT Trong Laravel 9

Dễ dàng thiết lập Xác thực dựa trên mã thông báo JWT trong Laravel . Quá trình tương tác truyền thống với một trang web là đăng nhập từ trang đăng nhập. Tiếp theo, bạn thực hiện các thao tác mong muốn rồi đăng xuất. Tuy nhiên, trong trường hợp của REST API , quá trình này hoàn toàn khác. JWT (Mã thông báo web JSON) thường được sử dụng để gửi thông tin có thể được tin cậy và xác minh bằng chữ ký điện tử.

Khi nào chúng ta có thể sử dụng Mã thông báo web JSON

Hãy để chúng tôi nói; bạn có một ứng dụng di động cần giao tiếp với máy chủ. Bây giờ, một máy chủ cần xác định người mà họ đang nói chuyện. Nhưng thật không may, HTTP là một giao thức không trạng thái. Vì vậy, chúng tôi cần tạo một cơ chế giải quyết vấn đề của chúng tôi: cách máy chủ sẽ xác định rằng người dùng là mới hay cũ. Nó đã được đăng ký với ứng dụng hay chưa. Nó có được ủy quyền cho người dùng hay không? Trong trường hợp đó, chúng ta có thể sử dụng Xác thực JWT .

Xác thực JWT Laravel

  1. Người dùng gửi yêu cầu đăng ký đến máy chủ và máy chủ tạo người dùng và mã thông báo JWT trên cơ sở dữ liệu đó và trả về mã thông báo JWT  dưới dạng phản hồi.
  2. JWT  được lưu trữ trong cục bộ của trình duyệt hoặc các cơ chế lưu trữ khác.
  3. Khi người dùng thực hiện một yêu cầu khác, người dùng cần thêm mã thông báo đó vào tiêu đề yêu cầu.
  4. Máy chủ đã kiểm tra mã thông báo đó và dựa trên việc mã thông báo JWT có hợp lệ hay không, nó trả về phản hồi.
  5. Cho đến khi người dùng đăng xuất khỏi ứng dụng và hủy mã thông báo đó khỏi bộ nhớ cục bộ, nó sẽ luôn kiểm tra nó. Nếu mã thông báo hợp lệ, thì nó có thể truy cập các tài nguyên cụ thể.
  6. Nếu mã thông báo bị phá hủy hoặc bị thao túng, người dùng sẽ chuyển hướng đến màn hình đăng nhập và anh ta cần điền tên người dùng và mật khẩu.
  7. Nếu tên người dùng và mật khẩu hợp lệ, thì theo phản hồi, nó sẽ gửi lại mã thông báo JWT cho người dùng. Sau đó, một lần nữa quy trình tương tự, người dùng lưu trữ nó trong bộ nhớ cục bộ và gửi mã thông báo đó cho mọi yêu cầu xác minh với máy chủ rằng anh ta có một người dùng đáng tin cậy và có thể truy cập các tài nguyên cụ thể.

Như thường lệ, chúng tôi bắt đầu dự án này bằng cách cài đặt Laravel mới.

 Bước 1: Cài đặt và cấu hình Laravel

Cài đặt Laravel bằng lệnh sau.

 

composer create-project laravel/laravel jwtauth --prefer-dist

Cấu hình cơ sở dữ liệu.

Bây giờ, hãy cài đặt gói jwtauth của bên thứ ba bằng cách gõ lệnh sau.

 

composer require tymon/jwt-auth

Nó sẽ cài đặt gói trong  thư mục nhà cung cấp  và tệp composer.json  của chúng tôi sẽ được cập nhật.

Bước 2: Cập nhật config / app.php cho gói JWT

Đi tới  tệp config >> app.php  và thêm phần sau.

'providers' => [
    ....
    'Tymon\JWTAuth\Providers\JWTAuthServiceProvider',
],
'aliases' => [
    ....
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
        'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],

Để xuất bản tệp cấu hình trong Laravel, bạn cần chạy dòng mã sau:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

Bây giờ để mã hóa mã thông báo, tôi cần tạo khóa bí mật bằng cách chạy dòng mã sau:

php artisan jwt:generate

Nếu bạn tìm thấy lỗi như thế này sau khi nhấn lệnh trên.

ReflectionException: Phương thức Tymon \ JWTAuth \ Commands \ JWTGenerateCommand :: handle () không tồn tại

Bạn cần thực hiện bước sau.

Đi tới tệp JWTGenerateCommand.php  nằm trong  nhà cung cấp / tymon / src / Commands và dán phần này của mã.public function handle() { $this->fire(); }

Bạn có thể tìm hiểu thêm về vấn đề này .

Bước 3: Đăng ký người dùng vào cơ sở dữ liệu.

Di chuyển các bảng vào cơ sở dữ liệu bằng lệnh sau.

php artisan migrate

Bây giờ, hãy tạo hai tệp bộ điều khiển để đăng ký và xác thực người dùng.

  1. APIRegisterController.php
  2. APILoginController.php

Vui lòng nhập lệnh sau để tạo nó.

php artisan make:controller APIRegisterController
php artisan make:controller APILoginController

Ngoài ra, hãy đăng ký các tuyến api bên trong  tệp route >> api.php  .

Route::post('user/register', 'APIRegisterController@register');
Route::post('user/login', 'APILoginController@login');

Đầu tiên, chúng tôi viết mã  hàm đăng ký  bên trong tệp APIRegisterController.php  .

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use JWTFactory;
use JWTAuth;
use Validator;
use Response;

class APIRegisterController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255|unique:users',
            'name' => 'required',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        User::create([
            'name' => $request->get('name'),
            'email' => $request->get('email'),
            'password' => bcrypt($request->get('password')),
        ]);
        $user = User::first();
        $token = JWTAuth::fromUser($user);
        
        return Response::json(compact('token'));
    }
}

Những gì tôi đã làm trước tiên là kiểm tra xác thực và sau đó nếu tất cả dữ liệu biểu mẫu có vẻ đúng, nó sẽ đăng ký người dùng trong cơ sở dữ liệu và trả về mã thông báo JWT. Chúng tôi đang tạo mã thông báo dựa trên đối tượng Người dùng. Bạn có thể tạo mã thông báo từ bất kỳ thứ gì bạn muốn. Bạn có thể tìm thêm hướng dẫn tại đây .

Bước 4: Kiểm tra trong Postman.

Chúng tôi đang đăng ký người dùng thông qua người đưa thư. Vì vậy, hãy để chúng tôi làm điều đó.

Đầu tiên, chúng tôi kiểm tra xác nhận.

Hướng dẫn xác thực API Laravel

 

Bây giờ, hãy điền tên, email và  mật khẩu  của bạn và xem liệu chúng tôi có thể nhận được mã thông báo hay không.

 

Hướng dẫn xác thực JWT Laravel 5.6

Rất tiếc !! Chúng tôi đã đăng ký thành công người dùng và lấy lại mã thông báo JWT. Bây giờ hãy lưu mã thông báo này vào bộ nhớ cục bộ và khi chúng ta cần truy cập vào bất kỳ tài nguyên được bảo vệ nào, hãy chuyển mã thông báo này dưới dạng Auth Bearer để nhận yêu cầu và có được tuyến đường đó.

Bước 5: Đăng nhập người dùng.

Chúng tôi đã xác định  đường đăng nhập  trong  tệp api.php  . Bây giờ, hãy truy cập tệp APILoginController.php  và mã  chức năng đăng nhập  .

// APILoginController.php

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
use JWTFactory;
use JWTAuth;
use App\User;
use Illuminate\Support\Facades\Auth;

class APILoginController extends Controller
{
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        $credentials = $request->only('email', 'password');
        try {
            if (! $token = JWTAuth::attempt($credentials)) {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        } catch (JWTException $e) {
            return response()->json(['error' => 'could_not_create_token'], 500);
        }
        return response()->json(compact('token'));
    }
}

Nếu email và mật khẩu chính xác, chúng tôi có thể tạo mã thông báo JWT. Nếu không, chúng tôi gặp lỗi. Bây giờ hãy kiểm tra điều này trong POSTMAN và xem liệu chúng ta có thể nhận được mã thông báo hay không.

 

Hướng dẫn xác thực API Laravel 5.6

Bước 6: Bao gồm phần mềm trung gian để bảo vệ tài nguyên.

Theo mặc định,  gói  tymondesigns / jwt -auth cung cấp cho chúng ta hai phần mềm trung gian.

  • jwt.auth

jwt.refresh

Chúng ta cần đăng ký các phần mềm trung gian này vào tệp ứng dụng >> Http >> Kernel.php  .

protected $routeMiddleware = [
...
...
'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
]

Xác định một tuyến đường cần được bảo vệ thông qua Xác thực mã thông báo JWT .

// api.php

Route::middleware('jwt.auth')->get('users', function(Request $request) {
    return auth()->user();
});

Bây giờ, đăng nhập vào ứng dụng và nhận mã thông báo. Chúng tôi có thể sử dụng mã thông báo này trong yêu cầu nhận như sau.

Authorization: Bearer {yourtokenhere}

 

Và, chúng tôi đang đưa Người dùng trở lại. Vì vậy,  Ví dụ Hướng dẫn Xác thực Laravel JWT  đầy đủ chức năng của chúng tôi đang hoạt động. Vì vậy, tôi đã đặt mã này trên Github. Vì vậy, hãy kiểm tra điều đó là tốt.

Liên kết: https://appdividend.com/2022/02/28/laravel-jwt-authentication/

#laravel #jwt

Hướng Dẫn Hoàn Chỉnh Về Xác Thực JWT Trong Laravel 9

Полное руководство по JWT-аутентификации в Laravel 9

Настроить аутентификацию на основе токенов JWT в Laravel очень просто. Традиционный процесс взаимодействия с веб-сайтом — вход со страницы входа. Затем вы выполняете желаемые действия, а затем выходите из системы. Однако в случае REST API процесс совершенно другой. JWT (веб-токен JSON) обычно используется для отправки информации, которой можно доверять и которую можно проверить с помощью цифровой подписи.

Когда мы можем использовать веб-токены JSON

скажем; у вас есть мобильное приложение, которому необходимо взаимодействовать с сервером. Теперь серверу необходимо определить, с кем он разговаривает. Но, к сожалению, HTTP — это протокол без сохранения состояния. Итак, нам нужно создать механизм, решающий нашу проблему: как сервер будет определять, является ли пользователь новым или старым. Он уже зарегистрирован в приложении или нет. Это авторизованный пользователь или нет? В этом случае мы можем использовать аутентификацию JWT .

JWT-аутентификация Laravel

  1. Пользователь отправляет запрос регистрации на сервер, и сервер создает пользователя и токен JWT в этой базе данных и возвращает токен JWT  в качестве ответа.
  2. JWT  хранится либо в локальном хранилище браузера, либо в других механизмах хранения.
  3. Когда пользователь делает другой запрос, ему необходимо добавить этот токен в заголовок запроса.
  4. Сервер проверил этот токен и в зависимости от того, действителен ли токен JWT, вернул ответ.
  5. Пока пользователь не выйдет из приложения и не удалит этот токен из локального хранилища, он всегда проверяет его. Если токен действителен, он может получить доступ к определенным ресурсам.
  6. Если токен уничтожен или изменен, пользователь перенаправляется на экран входа в систему, и ему необходимо ввести имя пользователя и пароль.
  7. Если имя пользователя и пароль верны, то в ответ он отправляет токен JWT обратно пользователю. Затем, снова та же процедура, пользователь сохраняет его в локальном хранилище и отправляет этот токен для каждого запроса, чтобы проверить на сервере, что у него есть доверенный пользователь и он может получить доступ к определенным ресурсам.

Как обычно, мы начинаем этот проект с установки свежего Laravel.

 Шаг 1: Установите и настройте Laravel

Установите Laravel с помощью следующей команды.

 

composer create-project laravel/laravel jwtauth --prefer-dist

Настройте базу данных.

Теперь установите сторонний пакет jwtauth , введя следующую команду.

 

composer require tymon/jwt-auth

Он установит пакет в  папку поставщика  , и наш файл composer.json  будет обновлен.

Шаг 2: Обновите config/app.php для пакета JWT.

Перейдите в  файл config >> app.php  и добавьте следующее.

'providers' => [
    ....
    'Tymon\JWTAuth\Providers\JWTAuthServiceProvider',
],
'aliases' => [
    ....
    'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
        'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],

Чтобы опубликовать файл конфигурации в Laravel, вам нужно запустить следующую строку кода:

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

Теперь для шифрования токена мне нужно сгенерировать секретный ключ, выполнив следующую строку кода:

php artisan jwt:generate

Если вы обнаружите подобную ошибку после нажатия вышеуказанной команды.

ReflectionException: метод Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() не существует

Вам необходимо сделать следующий шаг.

Перейдите к файлу JWTGenerateCommand.php  , расположенному в  vendor/tymon/src/Commands , и вставьте эту часть кода.public function handle() { $this->fire(); }

Вы можете узнать больше об этой проблеме .

Шаг 3: Зарегистрируйте пользователя в базе данных.

Перенесите таблицы в базу данных с помощью следующей команды.

php artisan migrate

Теперь создайте два файла контроллера для регистрации и аутентификации пользователей.

  1. APIRegisterController.php
  2. APIЛогинКонтроллер.php

Пожалуйста, введите следующую команду, чтобы сгенерировать его.

php artisan make:controller APIRegisterController
php artisan make:controller APILoginController

Кроме того, зарегистрируйте маршруты API внутри  файла route >> api.php  .

Route::post('user/register', 'APIRegisterController@register');
Route::post('user/login', 'APILoginController@login');

Во-первых, мы  кодируем функцию регистрации  внутри файла APIRegisterController.php  .

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use JWTFactory;
use JWTAuth;
use Validator;
use Response;

class APIRegisterController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255|unique:users',
            'name' => 'required',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        User::create([
            'name' => $request->get('name'),
            'email' => $request->get('email'),
            'password' => bcrypt($request->get('password')),
        ]);
        $user = User::first();
        $token = JWTAuth::fromUser($user);
        
        return Response::json(compact('token'));
    }
}

Что я сделал, так это сначала проверил проверку, а затем, если все данные формы кажутся правильными, он зарегистрирует пользователя в базе данных и вернет токен JWT. Мы генерируем токен на основе объекта User. Вы можете создать токен из чего угодно. Дополнительные рекомендации можно найти здесь .

Шаг 4: Протестируйте в Postman.

Регистрируем пользователя через postman. Итак, давайте сделаем это.

Во-первых, мы проверяем валидацию.

Учебное пособие по аутентификации API Laravel

 

Теперь введите свое имя, адрес электронной почты и  пароль  и посмотрите, сможем ли мы получить токен или нет.

 

Учебное пособие по аутентификации JWT в Laravel 5.6

Ой!! Мы успешно зарегистрировали пользователя и получили токен JWT. Теперь сохраните этот токен в локальном хранилище, и когда нам понадобится доступ к любому защищенному ресурсу, передайте этот токен как Auth Bearer, чтобы получить запрос и получить этот маршрут.

Шаг 5: Войдите в систему.

Мы уже определили  маршрут  входа  в файл api.php  . Теперь перейдите к файлу APILoginController.php  и  закодируйте функцию входа  в систему .

// APILoginController.php

<?php

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
use JWTFactory;
use JWTAuth;
use App\User;
use Illuminate\Support\Facades\Auth;

class APILoginController extends Controller
{
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|string|email|max:255',
            'password'=> 'required'
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors());
        }
        $credentials = $request->only('email', 'password');
        try {
            if (! $token = JWTAuth::attempt($credentials)) {
                return response()->json(['error' => 'invalid_credentials'], 401);
            }
        } catch (JWTException $e) {
            return response()->json(['error' => 'could_not_create_token'], 500);
        }
        return response()->json(compact('token'));
    }
}

Если адрес электронной почты и пароль верны, мы можем сгенерировать токен JWT. В противном случае получаем ошибку. Теперь проверьте это в POSTMAN и посмотрите, сможем ли мы получить токен.

 

Учебное пособие по аутентификации API Laravel 5.6

Шаг 6: Включите промежуточное ПО для защиты ресурсов.

Пакет tymondesigns jwt  -auth по умолчанию предоставляет нам два промежуточных ПО.

  • jwt.auth

jwt.refresh

Нам нужно зарегистрировать эти промежуточные программы в файле app >> Http >> Kernel.php  .

protected $routeMiddleware = [
...
...
'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
]

Определите один маршрут, который необходимо защитить с помощью JWT Token Authentication .

// api.php

Route::middleware('jwt.auth')->get('users', function(Request $request) {
    return auth()->user();
});

Теперь войдите в приложение и получите токен. Мы можем использовать этот токен в запросе на получение следующим образом.

Authorization: Bearer {yourtokenhere}

 

И мы возвращаем пользователя. Итак, наш полнофункциональный  пример Laravel JWT Authentication Tutorial  работает. Итак, я разместил этот код на Github. Так что, пожалуйста, проверьте и это.

Ссылка: https://appdividend.com/2022/02/28/laravel-jwt-authentication/

#laravel #jwt

Полное руководство по JWT-аутентификации в Laravel 9