JWT 双签发认证 + RBAC 权限

1. JWT 双签发认证基础概念

JWT(JSON Web Token)是一种用于在网络应用间传递声明的安全标准。双签发认证指的是同时签发访问令牌(Access Token)和刷新令牌(Refresh Token):

  • Access Token:包含用户身份和权限信息,有效期较短(如 15 分钟)
  • Refresh Token:仅包含用户身份信息,有效期较长(如 7 天)
  • 当 Access Token 过期时,使用 Refresh Token 重新获取新的 Access Token

2. RBAC 权限模型基础概念

RBAC(基于角色的访问控制)是一种权限管理模型,核心组件包括:

  • 用户(User):系统的使用者
  • 角色(Role):一组权限的集合(如管理员、用户、访客)
  • 权限(Permission):对资源的操作许可(如创建文章、删除用户)
  • 用户 - 角色关联:一个用户可以拥有多个角色
  • 角色 - 权限关联:一个角色可以包含多个权限

3. Java 项目中实现 JWT 双签发认证

以下是一个简单的 Java 实现示例,使用 Spring Security 和 JJWT 库:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtUtil {
    private static final String SECRET_KEY = "your-secret-key";
    private static final long ACCESS_TOKEN_VALIDITY = 15 * 60 * 1000; // 15分钟
    private static final long REFRESH_TOKEN_VALIDITY = 7 * 24 * 60 * 60 * 1000; // 7天

    // 生成访问令牌
    public String generateAccessToken(String username, String roles) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("roles", roles);
        return createToken(claims, username, ACCESS_TOKEN_VALIDITY);
    }

    // 生成刷新令牌
    public String generateRefreshToken(String username) {
        return createToken(new HashMap<>(), username, REFRESH_TOKEN_VALIDITY);
    }

    private String createToken(Map<String, Object> claims, String subject, long validity) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + validity))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // 验证令牌
    public Boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // 从令牌中获取用户名
    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    // 从令牌中获取角色
    public String getRolesFromToken(String token) {
        return (String) getAllClaimsFromToken(token).get("roles");
    }

    private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
    }
}

4. Java 项目中实现 RBAC 权限控制

下面是一个基于 Spring Security 的 RBAC 实现示例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final JwtRequestFilter jwtRequestFilter;

    public SecurityConfig(JwtRequestFilter jwtRequestFilter) {
        this.jwtRequestFilter = jwtRequestFilter;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/api/auth/**").permitAll() // 认证接口不需要权限
                .antMatchers("/api/admin/**").hasRole("ADMIN") // 需要ADMIN角色
                .antMatchers("/api/user/**").hasAnyRole("ADMIN", "USER") // 需要ADMIN或USER角色
                .anyRequest().authenticated()
                .and()
            .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
}

5. 数据库五层设计方案

一个完整的 RBAC 系统数据库设计通常包含以下五层:

第一层:用户层
CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    status TINYINT NOT NULL DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
第二层:角色层
CREATE TABLE roles (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    role_name VARCHAR(50) UNIQUE NOT NULL,
    description VARCHAR(255),
    status TINYINT NOT NULL DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
第三层:权限层
CREATE TABLE permissions (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    permission_name VARCHAR(50) UNIQUE NOT NULL,
    description VARCHAR(255),
    status TINYINT NOT NULL DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
第四层:关联层
-- 用户-角色关联表
CREATE TABLE user_roles (
    user_id BIGINT NOT NULL,
    role_id BIGINT 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 BIGINT NOT NULL,
    permission_id BIGINT NOT NULL,
    PRIMARY KEY (role_id, permission_id),
    FOREIGN KEY (role_id) REFERENCES roles(id),
    FOREIGN KEY (permission_id) REFERENCES permissions(id)
);
第五层:资源层(可选,用于更细粒度控制)
CREATE TABLE resources (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    resource_name VARCHAR(50) UNIQUE NOT NULL,
    resource_type VARCHAR(50) NOT NULL,
    parent_id BIGINT,
    url VARCHAR(255),
    status TINYINT NOT NULL DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (parent_id) REFERENCES resources(id)
);

-- 权限-资源关联表
CREATE TABLE permission_resources (
    permission_id BIGINT NOT NULL,
    resource_id BIGINT NOT NULL,
    actions VARCHAR(100) NOT NULL, -- 如: "create,read,update,delete"
    PRIMARY KEY (permission_id, resource_id),
    FOREIGN KEY (permission_id) REFERENCES permissions(id),
    FOREIGN KEY (resource_id) REFERENCES resources(id)
);

6. 实现流程示例

以下是一个典型的认证授权流程:

  1. 用户登录,验证用户名密码
  2. 验证成功后,生成 Access Token 和 Refresh Token
  3. 将两个 Token 返回给客户端
  4. 客户端在请求头中携带 Access Token
  5. 服务端验证 Access Token 有效性
  6. 若 Access Token 过期,客户端使用 Refresh Token 请求新的 Access Token
  7. 服务端验证 Refresh Token,生成新的 Access Token 和 Refresh Token
  8. 服务端根据 Token 中的角色信息,结合 RBAC 权限控制进行访问控制

7. 安全增强建议

  1. Refresh Token 存储安全

    • 考虑将 Refresh Token 存储在 HttpOnly Cookie 中,防止 XSS 攻击
    • 对 Refresh Token 实现严格的同源策略
  2. Token 泄露防护

    • 实现 Token 撤销机制
    • 为每个用户维护一个唯一的设备标识
    • 实现异常登录检测和通知
  3. 权限设计最佳实践

    • 遵循最小权限原则
    • 定期审查和清理过时角色和权限
    • 实现权限继承和权限组
<think>好的,我现在需要帮助用户了解如何使用JWT实现用户登录和权限控制。首先,我需要回忆一下JWT的基本概念和工作流程。JWT是JSON Web Token的缩写,通常用于身份验证和授权。用户登录后,服务器生成一个JWT,客户端之后在请求中携带这个Token,服务器验证Token的合法性并据此授权。 根据用户提供的引用内容,他们提到了Shiro和JWT的整合,以及权限管理的实现。可能用户对如何在Spring Boot项目中结合这两个技术感兴趣。不过用户的问题更偏向于JWT本身如何实现登录和权限管理,而不仅仅是整合框架。 首先,我应该分步骤解释JWT的登录流程。用户登录时提交凭证,服务器验证凭证,生成JWT并返回。客户端存储JWT,通常在localStorage或cookie中。之后的每个请求都需要携带JWT,服务器验证JWT的有效性,并从中提取用户信息进行权限判断。 接下来是权限控制部分。JWT的Payload部分可以包含用户角色和权限信息。服务器在验证Token后,需要根据这些信息决定用户是否有权访问特定资源。例如,使用中间件或拦截器来检查权限,或者在API网关处理。 需要注意JWT的安全性,比如使用HTTPS传输,设置合理的过期时间,以及处理Token的刷新机制。此外,JWT是无状态的,所以服务器不需要保存会话信息,但这也意味着一旦签发,无法中途撤销,除非等到过期。 用户可能还会关心如何实际编码实现,比如生成Token的库,如何解析和验证签名,以及如何处理常见的权限控制场景,比如基于角色的访问控制(RBAC)。可能需要提到一些代码示例,比如使用Java的jjwt库,或者在Node.js中使用jsonwebtoken。 还要注意引用的内容中提到了Shiro的整合,所以可能需要比较JWT与传统会话管理的区别,以及为什么选择JWT,比如分布式系统的适用性。 另外,用户可能对JWT的结构(Header, Payload, Signature)不太清楚,需要简要解释。例如,Header包含算法类型,Payload包含声明(claims),如用户ID、角色,Signature用于验证消息未被篡改。 可能的问题点包括如何安全存储JWT,避免XSS和CSRF攻击,以及如何处理Token过期后的刷新。需要给出最佳实践建议,比如使用HttpOnly的cookie存储,而不是localStorage。 最后,生成相关问题时,要考虑用户可能想了解JWT的安全隐患、具体实现步骤、与其他认证方式的对比,或者在微服务架构中的应用。</think>### 如何使用JWT实现用户登录与权限控制 #### 一、JWT登录流程实现 1. **用户提交凭证** 用户通过登录接口发送用户名和密码(或其他凭证),例如: ```bash POST /login { "username": "admin", "password": "******" } ``` 2. **服务器验证并生成Token** 服务器验证凭证合法性,成功后生成JWTJWT包含三部分: - **Header**:指定算法类型(如HMAC SHA256)和Token类型 ```json { "alg": "HS256", "typ": "JWT" } ``` - **Payload**:存放用户标识、角色、权限和有效期 ```json { "sub": "user123", "roles": ["admin"], "permissions": ["create:user", "delete:post"], "exp": 1629999999 } ``` - **Signature**:使用密钥对前两部分签名,防止篡改 ```python signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret_key) ``` 3. **返回Token给客户端** 服务器通过响应体返回Token: ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.7d5b7j8g..." } ``` 客户端需将Token存储在安全位置(如`localStorage`或`HttpOnly Cookie`)[^2]。 --- #### 二、权限控制实现 1. **Token校验中间件** 在请求到达业务逻辑前,通过拦截器验证JWT: ```java public boolean preHandle(HttpServletRequest request, HttpServletResponse response) { String token = request.getHeader("Authorization"); try { Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); request.setAttribute("userRoles", claims.get("roles")); // 传递权限信息 return true; } catch (Exception e) { response.setStatus(401); // 无效Token返回401 return false; } } ``` 2. **基于角色的访问控制(RBAC)** - 使用注解标注接口所需权限: ```java @GetMapping("/admin") @RequiresRoles("admin") // Shiro注解示例 public ResponseEntity<?> adminResource() { ... } ``` - 自定义权限验证逻辑: ```python def check_permission(user_roles, required_role): return required_role in user_roles ``` --- #### 三、安全增强措施 | 措施 | 说明 | |---------------------|----------------------------------------------------------------------| | **HTTPS传输** | 防止Token在传输中被窃听 | | **短期有效期** | 设置`exp`字段(如30分钟),配合Refresh Token机制延长会话[^1] | | **黑名单管理** | 通过Redis记录主动注销的Token,在拦截器中二次校验 | | **密钥轮换** | 定期更换签名密钥,降低泄露风险 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值