跳到主要内容

认证授权

介绍

认证(Authentication)和授权(Authorization)是后端系统安全的基石。认证是验证用户身份的过程,确保用户是其声称的身份;授权是确定已认证用户对系统资源的访问权限的过程。有效的认证授权机制可以防止未授权访问,保护系统和数据的安全。

原理

认证原理

  • 知识因素:用户知道的信息,如密码、PIN码
  • 持有因素:用户拥有的物品,如手机、令牌
  • 生物因素:用户的生物特征,如指纹、面部识别
  • 多因素认证(MFA):结合多种认证因素,提高安全性
  • 会话管理:认证成功后维护用户会话状态
  • 单点登录(SSO):一次认证,多处使用
  • 联合认证:使用第三方身份提供商进行认证

授权原理

  • 自主访问控制(DAC):资源所有者控制访问权限
  • 强制访问控制(MAC):系统根据安全策略强制控制访问
  • 基于角色的访问控制(RBAC):根据用户角色分配权限
  • 基于属性的访问控制(ABAC):根据用户和资源属性动态决定权限
  • 最小权限原则:只授予用户完成工作所需的最小权限
  • 权限继承:子资源继承父资源的权限
  • 权限回收:定期或按需回收不再需要的权限

常见认证协议

  • OAuth 2.0:授权框架,允许第三方应用获取有限访问权限
  • OpenID Connect(OIDC):基于OAuth 2.0的身份认证协议
  • JWT(JSON Web Token):紧凑的URL安全令牌,用于表示声明
  • SAML(Security Assertion Markup Language):基于XML的身份验证协议
  • Kerberos:网络认证协议,使用票据验证身份

图示

认证授权流程
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 用户 │ │ 认证服务器 │ │ 资源服务器 │
└─────────┬─────┘ └─────────┬─────┘ └─────────┬─────┘
│ │ │
1. 请求认证 │ │ │
───────────► │ │
│ │ │
2. 提供凭证 │ │ │
◄────────── │ │
│ │ │
3. 验证凭证 │ │ │
───────────► │ │
│ │ │
4. 颁发令牌 │ │ │
◄────────── │ │
│ │ │
5. 请求资源 │ │ │
└───────────────────────► │
│ │
6. 验证令牌 │ │ │
└───────────────────────►
│ │
7. 授权决策 │ │ │
◄───────────────────────┘
│ │
8. 响应请求 │ │ │
◄───────────────────────┘ │

│ │ │
9. 返回资源 │ │ │
◄───────────────────────────────────────────────────────────┘

JWT结构
┌─────────────────────────────────────────────────────────────────┐
│ 头部 (Header) │
│ {"alg": "HS256", "typ": "JWT"} │
├─────────────────────────────────────────────────────────────────┤
│ 载荷 (Payload) │
│ {"sub": "1234567890", "name": "John Doe", "iat": 1516239022} │
├─────────────────────────────────────────────────────────────────┤
│ 签名 (Signature) │
│ HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) │
└─────────────────────────────────────────────────────────────────┘

RBAC模型
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 用户 │ │ 角色 │ │ 权限 │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
│ 多对多关系 │ 多对多关系 │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ 用户-角色-权限映射表 │
└─────────────────────────────────────────────────────────────────┘

实例

JWT认证示例 (Node.js)

const jwt = require('jsonwebtoken');
const express = require('express');
const app = express();
app.use(express.json());

// 密钥,实际应用中应存储在环境变量中
const SECRET_KEY = 'your-secret-key';

// 用户数据,实际应用中应存储在数据库中
const users = [
{ id: 1, username: 'admin', password: 'admin123', role: 'admin' },
{ id: 2, username: 'user', password: 'user123', role: 'user' }
];

// 登录接口
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);

if (!user) {
return res.status(401).json({ message: '认证失败' });
}

// 生成JWT令牌
const token = jwt.sign(
{ userId: user.id, username: user.username, role: user.role },
SECRET_KEY,
{ expiresIn: '1h' }
);

res.json({ token });
});

// 认证中间件
const authenticate = (req, res, next) => {
const authHeader = req.headers.authorization;

if (!authHeader) {
return res.status(401).json({ message: '未提供认证令牌' });
}

const token = authHeader.split(' ')[1];

try {
const decoded = jwt.verify(token, SECRET_KEY);
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({ message: '无效的认证令牌' });
}
};

// 授权中间件 - 检查是否为管理员
const authorizeAdmin = (req, res, next) => {
if (req.user && req.user.role === 'admin') {
next();
} else {
res.status(403).json({ message: '没有权限访问此资源' });
}
};

// 受保护的路由 - 所有认证用户可访问
app.get('/api/protected', authenticate, (req, res) => {
res.json({ message: `欢迎 ${req.user.username},这是受保护的资源` });
});

// 管理员路由 - 仅管理员可访问
app.get('/api/admin', authenticate, authorizeAdmin, (req, res) => {
res.json({ message: `欢迎管理员 ${req.user.username},这是管理员资源` });
});

const PORT = 3000;
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});

OAuth 2.0示例 (Spring Boot)

// 配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.loginPage("/login")
.defaultSuccessUrl("/home")
.and()
.logout()
.logoutSuccessUrl("/");
}
}

// 控制器
@Controller
public class HomeController {

@GetMapping("/")
public String index() {
return "index";
}

@GetMapping("/home")
public String home(Principal principal, Model model) {
model.addAttribute("name", principal.getName());
return "home";
}
}

RBAC实现示例 (数据库设计)

-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL
);

-- 角色表
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
description TEXT
);

-- 权限表
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
resource VARCHAR(100) NOT NULL,
action VARCHAR(50) NOT NULL
);

-- 用户-角色关联表
CREATE TABLE user_roles (
user_id INT NOT NULL,
role_id INT NOT NULL,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);

-- 角色-权限关联表
CREATE TABLE role_permissions (
role_id INT NOT NULL,
permission_id INT NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
);

-- 插入示例数据
INSERT INTO roles (name, description) VALUES
('admin', '管理员角色,拥有所有权限'),
('user', '普通用户角色,拥有基本权限');

INSERT INTO permissions (name, description, resource, action) VALUES
('read_user', '读取用户信息', 'user', 'read'),
('create_user', '创建用户', 'user', 'create'),
('update_user', '更新用户', 'user', 'update'),
('delete_user', '删除用户', 'user', 'delete');

INSERT INTO role_permissions (role_id, permission_id) VALUES
(1, 1), (1, 2), (1, 3), (1, 4), -- 管理员拥有所有权限
(2, 1); -- 普通用户只有读取权限

专业解决方案

认证策略

  • 密码策略:复杂性要求、定期更换、密码加密存储
  • 多因素认证:结合密码和其他认证因素,如短信验证码、认证器应用
  • 单点登录(SSO):实现一次登录,多系统访问
  • 无密码认证:使用生物识别、FIDO等技术替代密码
  • 会话管理:设置合理的会话超时时间,安全存储会话标识
  • 防暴力破解:登录失败次数限制、IP锁定
  • 凭证保护:加密存储密码(使用bcrypt、Argon2等算法),不在客户端存储敏感凭证

授权机制

  • RBAC实现:设计合理的角色体系,避免角色爆炸
  • ABAC实现:基于属性的动态授权,更灵活的访问控制
  • 权限细化:最小权限原则,只授予必要的权限
  • 权限审计:定期审查用户权限,回收不再需要的权限
  • 层次化权限:设计权限的层次结构,便于管理
  • 资源级权限:对具体资源进行权限控制
  • 条件性权限:基于时间、地点等条件的权限控制

JWT最佳实践

  • 密钥管理:安全存储密钥,定期轮换
  • 令牌有效期:设置合理的过期时间,避免长期有效
  • 令牌包含信息:只包含必要信息,避免敏感信息
  • 签名算法:使用强签名算法,如RS256而非HS256
  • 令牌刷新:实现令牌刷新机制,避免频繁登录
  • 令牌撤销:实现令牌撤销机制,应对令牌泄露
  • 传输安全:通过HTTPS传输令牌,避免明文传输

OAuth 2.0最佳实践

  • 授权类型选择:根据应用类型选择合适的授权流程
  • 客户端密钥保护:安全存储客户端密钥,避免硬编码
  • 重定向URI验证:严格验证重定向URI,防止开放重定向攻击
  • scope控制:最小权限scope,只请求必要的权限
  • PKCE:对于公共客户端,使用PKCE增强安全性
  • 令牌验证:资源服务器必须验证令牌的有效性
  • 状态参数:使用state参数防止CSRF攻击

安全会话管理

  • 会话标识生成:使用强随机数生成会话ID
  • 会话存储:安全存储会话数据,避免客户端存储敏感信息
  • 会话超时:设置合理的会话超时时间
  • 会话绑定:将会话与IP、用户代理等信息绑定
  • 会话轮换:登录成功后轮换会话ID
  • 登出处理:确保登出时彻底清除会话信息
  • 分布式会话:在分布式系统中使用Redis等实现会话共享

工具推荐

  • 认证库:Passport.js、Spring Security、Auth0、Okta
  • JWT库:jsonwebtoken(Node.js)、jjwt(Java)、PyJWT(Python)
  • OAuth 2.0服务:Keycloak、IdentityServer、Auth0、Okta
  • 权限管理:Casbin、Shiro、Spring Security ACL
  • 密码加密:bcrypt、Argon2、scrypt
  • SSO解决方案:Active Directory、OAuth 2.0 + OIDC、SAML
  • 多因素认证:Google Authenticator、Authy、Duo Security