Microservice-Auth Service (3)

Microservice (3)

Untitled

  • Setup tsconfig with tsc —init
  • index.ts
  • Dockerfile Dockerignore
  • auth-depl.yaml
  • ingress-srv.yaml
  • skaffold.yml skaffold dev

As we are using microservice architecture, we need to standardize the way of transmitting errors to clients.

We can create a specific error handler (with four params) to handle all errors!

1
2
3
4
5
6
7
8
9
10
11
import { ValidationError } from "express-validator";

export class RequestValidationError extends Error {
constructor(public errors: ValidationError[]) {
super();


//Only because we are extending a built in class
Object.setPrototypeOf(this, RequestValidationError.prototype);
}
}

Untitled

We can use abstract class that force the custom error class to implement several functionalities

Check the code base for details

MongoDB

We will create One MongoDB for one service

这里和microservice没太大关系, 具体看代码

注意,我们需要用

import "express-async-errors"; 不然在express里的 async 函数无法throw error!

Authentication

How to authenticate can be a difficult problem in Microservices

  1. Sync request (No Event Bus) with a centralized auth service: BAD:
    1. coupling
    2. single break point of the whole system
  2. Each service have its own JWT/Cookie to check BAD:
    1. Hard to implement
    2. cannot instantly reflect the current status of a user in all services as user has 100% control of the token!

Untitled

Right now ,our strategy is as follow:

  1. user login through auth service, issued with a 15 mins of token
  2. if a admin user sends a request to ban a user, a UserBanned event is emitted to Event Bus
  3. all services will be listening to this event, and store the banned user into its own redis cache for 15 mins
  4. If a user reached a service, service can know if it is allowed through redis !

Untitled

Cookie is sent through Set-Cookie and managed by the browser. Server side can normally be guaranteed requests will have to the access of the settled cookie

JWT is handled by client code but not the browser. JWT token is sent through header every time of the request.

Cookie’s expiration date can be ignored as it is handled by the browser.

JWT is a more common and easy to handle technique as it is understood by other languages easily.

One important advantage to use microservice is that services can be implemented by different languages!

Because of server side rendering, the first time a user request to a URL cannot attach any authentication information as normal SPA can do. Therefore, we must store the JWT in cookie! JWT itself is not secret. However, we can use Signing key to check if a JWT is verified or not.

We need cookie-session to store session data in cookie! , JWT is naturally temper-resistant,

Untitled

才发现,_id 会被 mongodb 自动转化为 property idof string type

Secrete in k8s

Secret object can be created and share through pods

Secret object can then be treated as env variable for all pods.

Imperative approach to create a secret object!

1
kubectl create secret generic jwt-secret --from-literal=JWT_KEY=asdf

We then can put the secret into the container through the Deployment

1
2
3
4
5
6
7
8
9
10
spec:
containers:
- name: auth
image: hughqing/auth
env:
- name: JWT_KEY
valueFROM:
secretKeyRef:
name: jwt-secret # the name of the secret
key: JWT_KEY

_id

JSON.stringify() can be overwritten by toJSON() function in the object

Testing

Main quesstion: What’s the scope of our tests?

  • Single middleware → Unit test
  • Single pipe
  • The whole service
  • different services?

没写这,如果要用直接看视频吧

We need to split the logic of Express App and Start Up into two files

Untitled

See code for details please!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
it("returns a 400 with missing email or password", async () => {
await request(app)
.post("/api/users/signup")
.send({
password: "[email protected]",
})
.expect(400);

return request(app)
.post("/api/users/signup")
.send({
email: "[email protected]",
})
.expect(400);
});

总结以下本小结:

  • One MongoDB for each service!
  • import "express-async-errors"; 不然在express里的 async 函数无法throw error!
  • Authentication can be difficult:
    • Sync request (No Event Bus) with a centralized auth service:
      • coupling
      • single break point of the whole system
    • Each service have its own JWT/Cookie to check
      • Hard to implement
      • cannot instantly reflect the current status of a user in all services as user has 100% control of the token
  • Our stategy: Right now ,our strategy is as follow:
    1. user login through auth service, issued with a 15 mins of token
    2. if a admin user sends a request to ban a user, a UserBanned event is emitted to Event Bus
    3. all services will be listening to this event, and store the banned user into its own redis cache for 15 mins
    4. If a user reached a service, service can know if it is allowed through redis !
  • JSON.stringify() can be overwritten by toJSON() function in the object
  • 才发现,_id 会被 mongodb 自动转化为 property idof string type
  • Test 看代码