Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Authentication Micro-Service based on JWT Specification

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

This article is translated and published by the official account EAWorld, and the source should be indicated when reprinted.

Author: Marcelo Fonseca

Translator: Bai Xiaobai

Original title: Building an authentication micro-service with JWT standard

Original: http://t.cn/EI67VmL

The full text is 2326 words, and it takes about 5 minutes to read.

Table of contents:

I. introduction of micro-services

Second, the problems of authentication and authorization that follow

III. Project architecture communication

Public and private key tokens for signature and verification

V. synchronization of project database

I. introduction of micro-services

Micro services are becoming more and more popular, and almost all popular languages provide two framework implementations, one is a large framework for Web development, and the other is a micro framework for small applications. Lightweight framework is a good choice as a micro-service architecture. Micro-service architecture has many advantages, such as high maintainability, independent deployment and so on. Micro-service architecture allows us to choose the best solution for a specific language to build specific services, for example, for crawler applications or AI scenarios, we can choose to build a Python service; build JS services for encrypted library scenarios; build Ruby services for Active Record scenarios, and so on. Based on this idea, we do not need to be limited to using a single language to build the entire back-end service.

Here is a list of microframeworks available in various languages:

Python-Flask

Javascript-ExpressJS

Ruby-Sinatra

Go-Martini

Java-Spark

C #-nancy

C++-Crow

PHP-silex

Second, the problems of authentication and authorization that follow

Under the micro-service architecture, the authentication logic of the front and back end is much more complex than that of conventional CS applications. The client does not have an one-to-one relationship with the back-end API server. We need to manage a lot of back-end services and protect more application routes. In order to solve this problem, people have practiced many ways to establish authentication and authorization logic under the micro-service architecture. This article shows one of the solutions to implement a simple authentication and authorization service based on the JSON Web Tokens (JWT) standard.

III. Project architecture communication

For simplicity, only two back-end services are implemented in the example. I will build an expressJS application for authentication and authorization, as well as a Sinatra application to serve as the back end of the blog service. So far, in this example, there will be two backends and one front end.

The following describes the implementation mechanism of inter-application communication.

Front and back end communication mechanism

ExpressJS realizes the user registration and login of the front-end application.

If the authentication is successful, the ExpressJS application will return a JWT token.

The front end appends this token to the requested header to access the Sinatra application data.

Inter-service communication mechanism

When we need to implement communication between backends, we need to take advantage of such a mechanism. As an example scenario, assume that there is also a Flask API backend for crawling content on the web and updating data in the Sinatra blog application. So we have a total of three backends and one front end.

The Flask application requests a JWT token from the ExpressJS application.

After the request is successful, the ExpressJS application returns the token.

The Flask application appends a token to the header of the request and accesses the back-end route of the Sinatra application.

There are two things to note here. Whether the user makes a request or the backend sends a request, a legal identity is required to authenticate and access other backends. However, as a back-end service, email and password are not used. Instead, the API key is used as proof of identity. For example, the Flask application sends a login key to the route of the ExpressJS application, and as long as the key is correct, it can authorize the Flask service to obtain a JWT token.

IV. Used for signature and verification

Public and private key tokens

Under this architecture, all microservice applications will use their own JWT libraries to authenticate access requests and protect their API routing. We will use the JWT RSA256 policy here. The authentication service ExpressJS will hold both the private and public keys. Use the private key to sign the token of the user or application, and use the public key to decode and verify the token. Other services will hold only the public key for authentication.

Using the RSA algorithm requires the generation of a public / private key pair. It can be implemented in the terminal with the following code, which generates a .pem file as a result of execution:

Openssl genrsa-des3-out private.pem 2048openssl rsa-in private.pem-outform PEM-pubout-out public.pem

(swipe left and right to see all the code)

Sign token

Implement token signing in the login route of the user or API. The following code example shows the user login route for the ExpressJS authentication service. As long as the user's identity is legal, the code accesses the private key rsa2048priv.pem and signs a new JWT token.

/ / User sign-in route with JWT RSA algorithm example

Var User = require ('.. / models/user')

Var express = require ('express')

Var router = express.Router ()

Const mongoose = require ('mongoose')

Const bcrypt = require ('bcrypt')

Const jwt = require ('jsonwebtoken')

Const fs = require ('fs')

Router.route ('/ sign-in') .post (function (req, res, next) {

User.find ({email: req.body.email}) .then (user = > {

If (user.length {

If (success) {

Let cert = fs.readFileSync ('.. / rsa_2048_priv.pem')

Const token = jwt.sign (

{

Email: user [0] .email

/ / id: user [0]. _ id

}

Cert

{

ExpiresIn: '1h'

Algorithm: 'RS256'

Issuer: user [0] .role

}

);

Res.status. Json ({token: token, message: 'Successfully authenticated.'})

} else

Return res.status. Json ({message: 'Authentication failed.'})

});

});

});

(swipe left and right to see all the code)

Verify token

All services need to validate inbound requests with legitimate JWT tokens. This can be achieved by establishing a middleware in the application. This middleware accesses the public key pem file to decode and validate the token. In an ExpressJS or Sinatra service, such middleware code is similar to the following.

ExpressJS authentication and authorization middleware code:

/ / JWT authentication middleware example.

/ / Uses RS256 strategy with .pem key pair files.

Const fs = require ('fs')

Const jwt = require ('jsonwebtoken')

Module.exports = (req, res, next) = > {

Let publicKey = fs.readFileSync ('.. / rsa_2048_pub.pem')

Try {

Const token = req.headers.authorization.split ('') [1]; / / req.headers.token

Console.log (token)

Var decoded = jwt.verify (token, publicKey)

Console.log (decoded)

Next ()

} catch (err) {

Return res.status. Json ({error: err, message: 'Invalid token.'})

}

}

(swipe left and right to see all the code)

Sinatra authentication and authorization middleware code:

# To connect this middleware.rb file to your sinatra app

# add 'use JWTAuthorization' as one of your first lines in

# your Application class.

# e.g.

# require 'middlewares.rb'

# class Application

< Sinatra::Base # use JWTAuthorization # ... # end require 'sinatra/json' require 'jwt' class JWTAuthorization def initialize app @app = app end def call env begin # env.fetch gets http header # bearer = env.fetch('HTTP_AUTHORIZATION', '').split(' ')[1] # also work bearer = env.fetch('HTTP_AUTHORIZATION').slice(7..-1) # gets JWT token key = OpenSSL::PKey::RSA.new File.read '../rsa_2048_pub.pem' # read public key pem file payload = JWT.decode bearer, key, true, { algorithm: 'RS256'} # decode and verify token with pub key claims = payload.first # current_user is defined by env[:user]. # useful to define current_user if you are using pundit gem if claims['iss'] == 'user' env[:user] = User.find_by_email(claims['email']) end # access your claims here... @app.call env rescue JWT::DecodeError [401, { 'Content-Type' =>

'text/plain'}, [' A token must be passed.']]

Rescue JWT::ExpiredSignature

[403, {'Content-Type' = >' text/plain'}, ['The token has expired.']]

Rescue JWT::InvalidIssuerError

[403, {'Content-Type' = >' text/plain'}, ['The token does not have a valid issuer.']]

Rescue JWT::InvalidIatError

[403, {'Content-Type' = >' text/plain'}, ['The token does not have a valid "issued at" time.']]

# useful only if using pundit gem

Rescue Pundit::NotAuthorizedError

[401, {'Content-Type' = >' text/plain'}, ['Unauthorized access.']]

End

End

End

(swipe left and right to see all the code)

V. synchronization of project database

Separating the blog service from the authentication service will cause synchronization problems. One reason is that both need to save user information. ExpressJS needs to use the user's identity information, while Sinatra needs to use other user information (such as profile photos, personal descriptions and the relationship between posting and comment data, etc.). There are many solutions to this problem:

Scheme 1: save all user information in the user table of the authentication service. Only the user's ExpressJS service ID (that is, user_id) will be saved in the user table of the blog service to index and query user data in the authentication service.

Plan 2: there is no user table in the blog service. All blog database tables that involve user data will hold the ExpressJS user ID as an index.

Plan 3: only the identity information (such as email address and password) is saved in the authentication service, and the rest information is saved in the blog service. When you need to reference the user data of the authentication service in the blog service, it is associated with the user's ID or email address as the unique index. When using the email address, you need to save the user's email address in the blog service at the same time.

You can choose from the above options according to your actual situation. I will choose the third option and let each service save only the reasonable data it needs. In this way, with only a small amount of code modification, I can reuse this authentication service in future projects, in order to make full use of Ruby's Active Record mechanism for user relationship modeling and query in Sinatra applications. Be careful to keep user data synchronized between applications, for example, if you delete or create a new user information in the ExpressJS application, make sure that the change is synchronized to the Sinatra application.

About EAWorld: micro services, DevOps, data governance, mobile architecture original technology sharing, long press QR code to follow

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report