阿里云主机折上折
  • 微信号
Current Site:Index > Authentication and Authorization

Authentication and Authorization

Author:Chuan Chen 阅读数:33062人阅读 分类: Node.js

Authentication and authorization are core mechanisms for building secure applications. Authentication verifies user identity, while authorization determines which resources a user can access. In Node.js, these functionalities are typically implemented using middleware and libraries such as Passport, JWT, and OAuth2.0.

Basic Concepts of Authentication

Authentication is the process of verifying a user's identity. Common methods include username/password, social login, and API keys. In Node.js, bcrypt can be used to hash passwords for security.

const bcrypt = require('bcrypt');
const saltRounds = 10;

async function hashPassword(password) {
  const salt = await bcrypt.genSalt(saltRounds);
  return await bcrypt.hash(password, salt);
}

async function comparePassword(password, hash) {
  return await bcrypt.compare(password, hash);
}

Session Management and Cookies

HTTP is stateless, so session management is needed to track users. In Express, the express-session middleware can be used:

const session = require('express-session');

app.use(session({
  secret: 'your_secret_key',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
}));

JWT Authentication

JSON Web Token (JWT) is a stateless authentication method. It consists of three parts: header, payload, and signature. The jsonwebtoken library simplifies JWT generation and verification:

const jwt = require('jsonwebtoken');

const token = jwt.sign({ userId: 123 }, 'secret_key', { expiresIn: '1h' });

jwt.verify(token, 'secret_key', (err, decoded) => {
  if (err) throw err;
  console.log(decoded); // { userId: 123, iat: ..., exp: ... }
});

OAuth2.0 and Third-Party Login

OAuth2.0 allows users to log in via third-party services like Google or GitHub. Passport.js provides multiple strategies:

const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
    clientID: 'your_client_id',
    clientSecret: 'your_client_secret',
    callbackURL: '/auth/google/callback'
  },
  (accessToken, refreshToken, profile, done) => {
    // Handle user data
    done(null, profile);
  }
));

Authorization Implementation

Authorization determines what a user can do. Common models include RBAC (Role-Based Access Control) and ABAC (Attribute-Based Access Control). Here's an RBAC example:

function checkRole(role) {
  return (req, res, next) => {
    if (req.user.role !== role) {
      return res.status(403).send('Forbidden');
    }
    next();
  };
}

app.get('/admin', checkRole('admin'), (req, res) => {
  res.send('Admin Dashboard');
});

Fine-Grained Permission Control

For more granular control, ACL (Access Control List) or policy patterns can be used:

const permissions = {
  admin: ['read', 'write', 'delete'],
  user: ['read']
};

function checkPermission(action) {
  return (req, res, next) => {
    if (!permissions[req.user.role].includes(action)) {
      return res.status(403).send('Forbidden');
    }
    next();
  };
}

Security Best Practices

  1. HTTPS: Always use HTTPS for sensitive data transmission.
  2. CSRF Protection: Use the csurf middleware to prevent cross-site request forgery.
  3. Rate Limiting: Use express-rate-limit to prevent brute-force attacks.
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // Limit requests
});

app.use(limiter);

Common Vulnerabilities and Mitigations

  1. SQL Injection: Use parameterized queries or ORM libraries.
  2. XSS Attacks: Escape user input and use the helmet middleware.
  3. JWT Security: Avoid storing sensitive data in JWTs and set reasonable expiration times.
const helmet = require('helmet');
app.use(helmet());

Practical Case Study

Consider a blog platform where users can post articles, but only admins can delete them. Here's the implementation:

app.post('/articles', authenticateUser, (req, res) => {
  // User posts an article
});

app.delete('/articles/:id', authenticateUser, checkRole('admin'), (req, res) => {
  // Admin deletes an article
});

Performance Optimization

Authentication and authorization can become performance bottlenecks. Optimize by:

  1. Caching: Cache user permission data.
  2. Async Validation: Validate JWTs asynchronously.
  3. Minimize JWT Size: Avoid storing excessive data in JWTs.
const redis = require('redis');
const client = redis.createClient();

function cacheUserPermissions(userId, permissions) {
  client.setex(`perms:${userId}`, 3600, JSON.stringify(permissions));
}

Testing and Debugging

Write test cases to ensure authentication and authorization logic is correct. Use supertest for HTTP testing:

const request = require('supertest');

describe('Auth API', () => {
  it('should deny access without token', async () => {
    const res = await request(app).get('/protected');
    expect(res.statusCode).toEqual(401);
  });
});

Logging and Monitoring

Log authentication and authorization events for troubleshooting:

const winston = require('winston');

const logger = winston.createLogger({
  transports: [new winston.transports.File({ filename: 'auth.log' })]
});

app.use((req, res, next) => {
  logger.info(`${req.method} ${req.path} - ${req.user?.id || 'anonymous'}`);
  next();
});

Multi-Factor Authentication (MFA)

Enhance security with MFA, such as SMS codes or TOTP:

const speakeasy = require('speakeasy');

const secret = speakeasy.generateSecret();
const token = speakeasy.totp({
  secret: secret.base32,
  encoding: 'base32'
});

// Verify token
const verified = speakeasy.totp.verify({
  secret: secret.base32,
  encoding: 'base32',
  token: userToken,
  window: 1
});

Authentication in Microservices

In a microservices architecture, use an API gateway for centralized authentication or pass JWTs:

// Pass JWT between services
axios.get('http://service-b/data', {
  headers: { 'Authorization': `Bearer ${jwtToken}` }
});

Serverless Authentication

In serverless environments like AWS Lambda, use Cognito or Auth0:

exports.handler = async (event) => {
  const user = event.requestContext.authorizer.claims;
  return { statusCode: 200, body: JSON.stringify(user) };
};

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:输入验证

下一篇:会话管理

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.