这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*node_modules
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*node_modules
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM node:8.9.1

RUN mkdir -p /opt/app

RUN chown node:node /opt/app

WORKDIR /opt/app

COPY --chown=node:node package.json .

USER node

RUN npm install

COPY --chown=node:node . .

CMD npm start
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: npm start
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# JWT Authentication server Boilerplate

Sample JWT Authentication server for generating a JWT to use in the `Authentication` header by the built in JWT decoder in Hasura GraphQL Engine when started in JWT mode.

## Getting Started

### Deploy locally

#### Local Prerequisites

- PostgreSQL up and accepting connections
- Hasura GraphQL engine up and accepting connections
- Node.js 8.9+ installed

#### Local instructions

Install NPM dependencies

```bash
npm install
```

Set environment variables. Open `.env` file and add the following env

```bash
ENCRYPTION_KEY=<replace_it_with_your_JWT_SECRET>
DATABASE_URL=postgres://<username>:<password>@<host>:<port>/<database_name>
PORT=8080
```

##### User Schema

The following `users` table is assumed to be present in your schema. The table can have additional fields too.

| name | type | nullable | unique | default | primary |
| ---------- | ------- | -------- | ------ | ------- | ------- |
| id | Text | no | yes | | yes |
| name | Text | no | no | | no |
| password | Text | no | no | | no |
| created_at | Date | no | no | now() | |

Then start your app

```bash
npm start
```

## Usage

### Signup/Login

Once deployed or started locally, we can create an user using `/signup` API like below:

```bash
curl -H "Content-Type: application/json" \
-d'{"username": "test123", "password": "test123"}' \
http://localhost:8080/signup
```

On success, we get the response:

```json
{
"id": 1
}
```

We can also use `/login` API to fetch the user token:

```bash
curl -H "Content-Type: application/json" \
-d'{"username": "test123", "password": "test123"}' \
http://localhost:8080/login
```

On success, we get the response:

```json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsIm5hbWUiOiJ0ZXN0MTIzIiwiaWF0IjoxNTQwMjkyMzgyLjQwOSwiaHR0cHM6Ly9oYXN1cmEuaW8vand0L2NsYWltcyI6eyJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImVkaXRvciIsInVzZXIiLCJtb2QiXSwieC1oYXN1cmEtdXNlci1pZCI6MSwieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciJ9fQ.KtAUroqyBroBJL7O9og3Z4JnRkWNfr07cHQfeLarclU"
}
```

### Authenticate JWT using GraphQL Engine

The GraphQL engine comes with built in JWT authentication. You will need to start the engine with the same secret/key as the JWT auth server using the environment variable `HASURA_GRAPHQL_JWT_SECRET` (HASURA_GRAPHQL_ACCESS_KEY is also required see the docs)

In your GraphQL engine you will need to add permissions for a user named `user` with read permissions on the table and columns.

A sample CURL command using the above token would be:

```bash
curl -X POST \
http://localhost:8081/v1alpha1/graphql \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmFtZSI6InRlc3QxMjMiLCJpYXQiOjE1NDAzNzY4MTUuODUzLCJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsiZWRpdG9yIiwidXNlciIsIm1vZCJdLCJ4LWhhc3VyYS11c2VyLWlkIjoiMSIsIngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1yb2xlIjoidXNlciJ9fQ.w9uj0FtesZOFUnwYT2KOWHr6IKWsDRuOC9G2GakBgMI' \
-H 'Content-Type: application/json' \
-d '{ "query": "{ table { column } }" }'
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Module dependencies.
*/
require('dotenv').config();

const express = require('express');
const bodyParser = require('body-parser');
const chalk = require('chalk');
const dotenv = require('dotenv');
const passport = require('passport');
const expressValidator = require('express-validator');
const cors = require('cors');

/**
* Load environment variables from .env file, where API keys and passwords are configured.
*/
dotenv.load({ path: '.env' });

if(!process.env.ENCRYPTION_KEY) {
throw new Error('JWT encryption key required')
}

/**
* Create Express server.
*/
const app = express();
/**
* Express configuration.
*/
app.use(cors());
app.set('host', '0.0.0.0');
app.set('port', process.env.PORT || 8080);
app.set('json spaces', 2); // number of spaces for indentation
app.use(bodyParser.json());
app.use(expressValidator());
app.use(passport.initialize());
app.use(passport.session());

const userController = require('./controllers/user');

app.post('/login', userController.postLogin);
app.post('/signup', userController.postSignup);
/**
* Start Express server.
*/
app.listen(app.get('port'), () => {
console.log('%s App is running at http://localhost:%d in %s mode', chalk.green('✓'), app.get('port'), app.get('env'));
console.log(' Press CTRL-C to stop\n');
});

module.exports = app;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const passport = require('passport');
const { Strategy: LocalStrategy } = require('passport-local');
const { User } = require('../db/schema');

passport.use(
new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function (username, password, done) {
User
.query()
.where('id', username)
.first()
.then(function (user) {
if (!user) { return done('Unknown user'); }
user.verifyPassword(password, function (err, passwordCorrect) {
if (err) { return done(err); }
if (!passwordCorrect) { return done('Invalid password'); }
return done(null, user)
})
}).catch(function (err) {
done(err)
})
}
));

module.exports = passport;
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const passport = require('../config/passport');
const { User } = require('../db/schema');
const { errorHandler } = require('../db/errors');
const jwt = require('jsonwebtoken');

// Sign in using username and password.
exports.postLogin = async (req, res, next) => {
req.assert('username', 'email is not valid').notEmpty();
req.assert('password', 'Password cannot be blank').notEmpty();

const errors = req.validationErrors();

if (errors) {
return res.status(400).json({'errors': errors});
}

passport.authenticate('local', (err, user) => {
if (err) { return handleResponse(res, 400, {'error': err})}
if (user) {

const tokenContents = {
sub: user.id,
name: user.id.split('@')[0],
iat: Date.now() / 1000,
iss: 'https://learn.hasura.io/',
"https://hasura.io/jwt/claims": {
"x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": '' + user.id,
"x-hasura-default-role": "user",
"x-hasura-role": "user"
}
}

handleResponse(res, 200, {
token: jwt.sign(tokenContents, process.env.ENCRYPTION_KEY)
});
}
})(req, res, next);
};

// Signup using username and password.
exports.postSignup = async (req, res, next) => {
req.assert('username', 'email is not valid').notEmpty();
req.assert('password', 'Password must be at least 4 characters long').len(4);

const errors = req.validationErrors();

if (errors) {
return res.status(400).json({'errors': errors});
}

try {
await User.query()
.allowInsert('[id, name, password]')
.insert({
id: req.body.username,
name: req.body.username.split('@')[0],
password: req.body.password
});
} catch (err) {
errorHandler(err, res);
return;
}
passport.authenticate('local', (err, user, info) => {
if (err) { return handleResponse(res, 400, {'error': err})}
if (user) {
handleResponse(res, 200, user.getUser());
}
})(req, res, next);
};


function handleResponse(res, code, statusMsg) {
res.status(code).json(statusMsg);
}
Loading