forked from slava-lu/koa-jwt-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
183 lines (148 loc) · 6.07 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
const Koa = require('koa'); // ядро
const Router = require('koa-router'); // маршрутизация
const bodyParser = require('koa-bodyparser'); // парсер для POST запросов
const serve = require('koa-static'); // модуль, который отдает статические файлы типа index.html из заданной директории
const logger = require('koa-logger'); // опциональный модуль для логов сетевых запросов. Полезен при разработке.
const passport = require('koa-passport'); //реализация passport для Koa
const LocalStrategy = require('passport-local'); //локальная стратегия авторизации
const JwtStrategy = require('passport-jwt').Strategy; // авторизация через JWT
const ExtractJwt = require('passport-jwt').ExtractJwt; // авторизация через JWT
const jwtsecret = "mysecretkey"; // ключ для подписи JWT
const jwt = require('jsonwebtoken'); // аутентификация по JWT для hhtp
const socketioJwt = require('socketio-jwt'); // аутентификация по JWT для socket.io
const socketIO = require('socket.io');
const mongoose = require('mongoose'); // стандартная прослойка для работы с MongoDB
const crypto = require('crypto'); // модуль node.js для выполнения различных шифровальных операций, в т.ч. для создания хэшей.
const app = new Koa();
const router = new Router();
app.use(serve('public'));
app.use(logger());
app.use(bodyParser());
app.use(passport.initialize()); // сначала passport
app.use(router.routes()); // потом маршруты
const server = app.listen(3000);// запускаем сервер на порту 3000
mongoose.Promise = Promise; // Просим Mongoose использовать стандартные Промисы
mongoose.set('debug', true); // Просим Mongoose писать все запросы к базе в консоль. Удобно для отладки кода
mongoose.connect('mongodb://localhost/test', { useMongoClient: true }); // Подключаемся к базе test на локальной машине. Если базы нет, она будет создана автоматически.
mongoose.connection.on('error', console.error);
//---------Схема и модель пользователя------------------//
const userSchema = new mongoose.Schema({
displayName: String,
email: {
type: String,
required: 'Укажите e-mail',
unique: 'Такой e-mail уже существует'
},
passwordHash: String,
salt: String,
}, {
timestamps: true
});
userSchema.virtual('password')
.set(function (password) {
this._plainPassword = password;
if (password) {
this.salt = crypto.randomBytes(128).toString('base64');
this.passwordHash = crypto.pbkdf2Sync(password, this.salt, 1, 128, 'sha1');
} else {
this.salt = undefined;
this.passwordHash = undefined;
}
})
.get(function () {
return this._plainPassword;
});
userSchema.methods.checkPassword = function (password) {
if (!password) return false;
if (!this.passwordHash) return false;
return crypto.pbkdf2Sync(password, this.salt, 1, 128, 'sha1') == this.passwordHash;
};
const User = mongoose.model('User', userSchema);
//----------Passport Local Strategy--------------//
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
session: false
},
function (email, password, done) {
User.findOne({email}, (err, user) => {
if (err) {
return done(err);
}
if (!user || !user.checkPassword(password)) {
return done(null, false, {message: 'Нет такого пользователя или пароль неверен.'});
}
return done(null, user);
});
}
)
);
//----------Passport JWT Strategy--------//
// Ждем JWT в Header
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: jwtsecret
};
passport.use(new JwtStrategy(jwtOptions, function (payload, done) {
User.findById(payload.id, (err, user) => {
if (err) {
return done(err)
}
if (user) {
done(null, user)
} else {
done(null, false)
}
})
})
);
//------------Routing---------------//
//маршрут для создания нового пользователя
router.post('/user', async(ctx, next) => {
try {
ctx.body = await User.create(ctx.request.body);
}
catch (err) {
ctx.status = 400;
ctx.body = err;
}
});
//маршрут для локальной авторизации и создания JWT при успешной авторизации
router.post('/login', async(ctx, next) => {
await passport.authenticate('local', function (err, user) {
if (user == false) {
ctx.body = "Login failed";
} else {
//--payload - информация которую мы храним в токене и можем из него получать
const payload = {
id: user.id,
displayName: user.displayName,
email: user.email
};
const token = jwt.sign(payload, jwtsecret); //здесь создается JWT
ctx.body = {user: user.displayName, token: 'JWT ' + token};
}
})(ctx, next);
});
// маршрут для авторизации по токену
router.get('/custom', async(ctx, next) => {
await passport.authenticate('jwt', function (err, user) {
if (user) {
ctx.body = "hello " + user.displayName;
} else {
ctx.body = "No such user";
console.log("err", err)
}
} )(ctx, next)
});
//---Socket Communication-----//
let io = socketIO(server);
io.on('connection', socketioJwt.authorize({
secret: jwtsecret,
timeout: 15000
})).on('authenticated', function (socket) {
console.log('Это мое имя из токена: ' + socket.decoded_token.displayName);
socket.on("clientEvent", (data) => {
console.log(data);
})
});