首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

后端springboot中的jwt验证

基础概念

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用环境间安全地将信息作为JSON对象传输。在后端Spring Boot应用中,JWT常用于用户身份验证和信息传递。

优势

  1. 无状态:服务器不保存会话信息,减轻服务器压力。
  2. 安全性:使用签名算法确保数据不被篡改。
  3. 跨域支持:JWT可以在不同的域之间传递,适用于分布式系统。
  4. 扩展性:可以携带更多的自定义信息。

类型

  • 访问令牌(Access Token):用于访问资源。
  • 刷新令牌(Refresh Token):用于在访问令牌过期后获取新的访问令牌。

应用场景

  • 用户登录认证
  • API访问控制
  • 单点登录(SSO)

实现JWT验证的基本步骤

  1. 生成JWT:用户登录成功后,服务器生成一个包含用户信息的JWT并返回给客户端。
  2. 验证JWT:客户端在每次请求时携带JWT,服务器验证其有效性。

示例代码

以下是一个简单的Spring Boot应用中使用JWT进行身份验证的示例:

依赖配置

pom.xml中添加以下依赖:

代码语言:txt
复制
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

JWT工具类

创建一个JwtUtil类用于生成和验证JWT:

代码语言:txt
复制
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;

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

public class JwtUtil {

    private static final String SECRET_KEY = "yourSecretKey";

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, userDetails.getUsername());
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10小时过期
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

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

    private Boolean isTokenExpired(String token) {
        return Jwts.parser().setSigningKey(SECRET => 'yourSecretKey').parseClaimsJws(token).getBody().getExpiration().before(new Date());
    }
}

控制器示例

在控制器中使用JwtUtil进行身份验证:

代码语言:txt
复制
@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private AuthenticationManager authenticationManager;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody AuthenticationRequest authenticationRequest) throws Exception {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtUtil.generateToken((UserDetails) authentication.getPrincipal());

        return ResponseEntity.ok(new AuthenticationResponse(jwt));
    }

    @GetMapping("/user")
    public ResponseEntity<?> getCurrentUser(@RequestHeader("Authorization") String token) {
        if (token != null && token.startsWith("Bearer ")) {
            String jwtToken = token.substring(7);
            if (jwtUtil.validateToken(jwtToken, getCurrentAuthenticatedUser())) {
                String username = jwtUtil.extractUsername(jwtToken);
                // 返回用户信息
                return ResponseEntity.ok(new UserResponse(username));
            }
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

    private UserDetails getCurrentAuthenticatedUser() {
        // 获取当前认证的用户详情
    }
}

常见问题及解决方法

  1. JWT过期:客户端需要处理JWT过期的情况,通常是通过刷新令牌来获取新的访问令牌。
  2. JWT泄露:确保JWT在传输过程中不被泄露,可以使用HTTPS协议进行加密传输。
  3. 服务器时钟不同步:确保服务器时钟同步,以避免JWT过期时间验证失败。
  4. 签名算法选择:根据安全需求选择合适的签名算法,如HS256、RS256等。

参考链接

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

  • 使用SpringCloud将单体迁移到微服务

    CONFIG SERVER 这是一个很简单方式,但是也要防止程序员不小心一个delete数据库的灾难事情发生。 API网关 如果说后端微服务组成了一个服务群,这个群是群主的,群主可以批准你加入也可以剔除你,API网关就是微服务的守门人,专业上称为边缘服务,微服务是核心,它是边缘。 API网关的群主职责也还有其他: 1.设计上的适配层,或称Facade模式,后端微服务可能过于细粒度,通过API网关进行内外适配,前后端转换,如果220v转换成110v一样。 2.运行阶段:将外部请求路由分发到内部各个微服务,负载平衡和路由策略是需要的。 Springcloud之前使用NETFLIX ZUUL作为API网关,虽然它有很多好处,容易设置,限速和日志过滤,可授权,智能负载平衡,攻击探测和阻止,但是很难管理网关和API的超时。使用Spring ZUUL编程时,最大特征就是编制各种过滤器,事前过滤器 路由过滤器和事后过滤器。 在很多地方,也有使用Nginx作为API网关,Nginx官方有不少文章讲述Nginx如何在微服务架构中扮演重要角色的. NGINX和zuul 1.0是堵塞的,而Zuul 2.0、Spring Cloud Gateway和Linkerd, Envoy是非堵塞的,后两者借助API网关推出服务网格概念,能够统一对成千上百微服务进行管理,不过这好像又回到了服务器为王的时代,微服务好不容易打破服务器的约束,走出服务器的多租户空间独立成王,现在又会被打着API网关旗帜的新的统一管理方式关起来吗? SpringCloud提供Reactive响应式架构,使得分布式网络通讯效率大大提高,分布式系统的IO不再成为性能瓶颈。 服务发现 在分布式环境,许多服务实例都不断因为开发而不断变化,时而上线,时而下线,微服务之间如何好好发现活着的对方也是个问题,这就是需要服务注册器,每个微服务向其注册,其他需要调用的微服务通过注册器发现对方进行调用,调用时可加入负载平衡策略. Spring Cloud推荐使用NETFLIX EUREKA,用CAP定理来看,它属于AP,而Zookeeper属于CP,因此后者不是非常适合应用在服务发现场合,它本来诞生于大数据应用场景,虽然后来被Hadoop抛弃。 NETFLIX EUREKA易于设置,基于Rest的服务注册,支持复制,支持客户端缓存,速度快虽然数据容易不一致(AP)。 如果直接基于Eureka进行服务注册和发现,需要手工将负载平衡策略与REST处理绑定在一起,而通过Feign组件能够默认实现负载平衡+REST方式的通讯,只要像普通REST调用即可,大大提高了开发效率,其内部使用Ribbon负载平衡器和hystrix断路器。

    04
    领券