Skip to content

Commit

Permalink
Init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
icebob committed Nov 10, 2018
0 parents commit 99e4b43
Show file tree
Hide file tree
Showing 14 changed files with 1,885 additions and 0 deletions.
61 changes: 61 additions & 0 deletions .gitignore
@@ -0,0 +1,61 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next
35 changes: 35 additions & 0 deletions .vscode/launch.json
@@ -0,0 +1,35 @@
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach by Process ID",
"processId": "${command:PickProcess}"
},
{
"type": "node",
"request": "launch",
"name": "Debug",
"program": "${workspaceRoot}/node_modules/moleculer/bin/moleculer-runner.js",
"cwd": "${workspaceRoot}",
"args": [
"services"
]
},
{
"type": "node",
"request": "launch",
"name": "Jest",
"program": "${workspaceRoot}/node_modules/jest-cli/bin/jest.js",
"args": ["--runInBand"],
"cwd": "${workspaceRoot}",
"runtimeArgs": [
"--nolazy"
]
}
]
}
86 changes: 86 additions & 0 deletions README.md
@@ -0,0 +1,86 @@
[![Moleculer](https://img.shields.io/badge/Powered%20by-Moleculer-green.svg?colorB=0e83cd)](https://moleculer.services)

# moleculer-protect-services
This repo demonstrates how to use JWT token to protect service actions. It contains a `ServiceGuard` middleware and a `guard` service which implement this feature.

## Setup

1. Generate JWT token for every service. Use the `call guard.generate --service myService` command in REPL to generate a JWT for a service. The received token put into `authToken` property in service schema:

```js
module.exports = {
name: "users",

authToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXJ2aWNlIjoidXNlcnMiLCJpYXQiOjE1NDE4NTU0ODl9.td1P27_xpFv1P5_j0HLtMwyz-aRF9xQqjLHYIIHcKPE",

...
}
```
> In production you had better place it into environment variables like `USERS_AUTH_TOKEN` and use `authToken: process.env.USERS_AUTH_TOKEN` in schema
2. Define restriction in action definition. If `restricted` property is `null` or not defined it means the action can be called from every service.

```js
actions: {
create: {
// It can be called by "api" service
restricted: [
"api"
],
handler(ctx) {}
},

list: {
// It can be called by everyone.
restricted: null,
handler(ctx) {}
},

posts: {
// It can be called by "api" & "posts" service.
restricted: [
"api",
"posts"
],
handler(ctx) {}
}
},
```

3. Add `ServiceGuard` middleware to `moleculer.config.js`

```js
module.exports = {
logger: true,
logLevel: "info",

middlewares: [
ServiceGuard
]
};
```

## Try

**Try the following command in REPL:**
- `call users.create` - throw error because it is called directly, not from the `api` service
- `call users.list` - returns "OK" because it is not restricted
- `call users.posts` - throw error because it is called directly, not from `api` or `posts` service

- `call posts.createUser` - throw error because it is called from `posts` service and not from `api` service
- `call posts.userPosts` - returns "OK" because it is called from `posts` service.

- open http://localhost:3000/api/users/create in the browser - returns "OK" because it is called from the `api` service.


## Start

``` bash
# Install dependencies
npm install

# Start with REPL
npm run dev

```

51 changes: 51 additions & 0 deletions middlewares/ServiceGuard.js
@@ -0,0 +1,51 @@
const { MoleculerClientError } = require("moleculer").Errors;

module.exports = {

// Wrap local action handlers (legacy middleware handler)
localAction(next, action) {
// If this feature enabled
if (action.restricted) {

// Create new handler
return async function ServiceGuardMiddleware(ctx) {
// Check the service auth token in Context meta
const token = ctx.meta.$authToken;
if (!token)
throw new MoleculerClientError("Service token is missing", 401, "TOKEN_MISSING");

// Verify token & restricted services
await ctx.call("guard.check", { token, services: action.restricted })

// Call the original handler
return await next(ctx);

}.bind(this);
}

// Return original handler, because feature is disabled
return next;
},

// Wrap broker.call method
call(next) {
// Create new handler
return async function(actionName, params, opts = {}) {
// Put the service auth token in the meta
if (opts.parentCtx) {
const service = opts.parentCtx.service;
const token = service.schema.authToken;

if (!opts.meta)
opts.meta = {};

opts.meta.$authToken = token;
}

// Call the original handler
return await next(actionName, params, opts);

}.bind(this);
},

};
13 changes: 13 additions & 0 deletions moleculer.config.js
@@ -0,0 +1,13 @@
"use strict";

const ServiceGuard = require("./middlewares/ServiceGuard");

// More info about options: https://moleculer.services/docs/0.13/broker.html#Broker-options
module.exports = {
logger: true,
logLevel: "info",

middlewares: [
ServiceGuard
]
};

0 comments on commit 99e4b43

Please sign in to comment.