User.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. const mongoose = require('mongoose');
  2. const { Schema } = mongoose;
  3. const bcrypt = require('bcryptjs');
  4. const jwt = require('jsonwebtoken');
  5. const userSchema = new Schema({
  6. username: { type: String, required: true, unique: true },
  7. password: { type: String, required: true },
  8. roles: { type: [String], default: ['user'] },
  9. }, { timestamps: true });
  10. const User = mongoose.model('User', userSchema);
  11. const add = async ({ username, password } = {}) => {
  12. return User.findOne({ username })
  13. .then(existing => {
  14. if (existing) {
  15. return Promise.reject(new Error('USER_EXISTS'));
  16. }
  17. return bcrypt.hash(password, 10);
  18. })
  19. .then(hashedPassword => {
  20. const user = new User({ username, password: hashedPassword });
  21. return user.save();
  22. });
  23. }
  24. const login = async ({ username, password } = {}) => {
  25. return User.findOne({ username })
  26. .then(user => {
  27. if (!user) {
  28. return Promise.reject(new Error('USER_NOT_FOUND'));
  29. }
  30. return Promise.all([
  31. bcrypt.compare(password, user.password),
  32. Promise.resolve(user),
  33. ]);
  34. })
  35. .then(([isMatch, user]) => {
  36. if (!isMatch) {
  37. return Promise.reject(new Error('PASSWORD_ERROR'));
  38. }
  39. return user;
  40. })
  41. .then(user => {
  42. // 签发 Access Token 和 Refresh Token
  43. const accessToken = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '30m' });
  44. const refreshToken = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' });
  45. const userInfo = {
  46. uid: user._id.toString(),
  47. username: user.username,
  48. roles: user.roles ?? ['user'],
  49. }
  50. return { info: userInfo, accessToken, refreshToken };
  51. });
  52. }
  53. const refresh = async (refreshToken) => {
  54. const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET);
  55. return User.findById(decoded.userId)
  56. .then(user => {
  57. if (!user) {
  58. return Promise.reject(new Error('USER_NOT_FOUND'));
  59. }
  60. // 签发新的 Access Token
  61. const newAccessToken = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '30m' });
  62. return newAccessToken;
  63. });
  64. }
  65. const info = async (userId) => {
  66. return User.findById(userId).select('-password')
  67. .then(user => {
  68. if (!user) {
  69. return Promise.reject(new Error('USER_NOT_FOUND'));
  70. }
  71. return {
  72. uid: user._id.toString(),
  73. username: user.username,
  74. roles: user.roles ?? ['user'],
  75. };
  76. });
  77. }
  78. const init = async ({ username, password } = {}) => {
  79. return User.find()
  80. .then(users => {
  81. if (users.length) {
  82. return Promise.reject('USER_EXISTS');
  83. }
  84. return bcrypt.hash(password, 10);
  85. })
  86. .then(hashedPassword => {
  87. const user = new User({
  88. username,
  89. password: hashedPassword,
  90. roles: ['admin'],
  91. });
  92. return user.save();
  93. });
  94. }
  95. module.exports = { add, login, refresh, info, init };