Spring Boot 集成JWT实现前后端认证的示例代码

下面是关于“Spring Boot集成JWT实现前后端认证的示例代码”的完整攻略。

1. 什么是JWT

JWT全称为JSON Web Token,是一种基于JSON的轻量级标准,我们可以使用JWT实现前后端的认证功能。其中,JWT由三部分组成:Header、Payload、Signature。Header和Payload分别是一个JSON对象(字典),而Signature则是对Header、Payload加密后的结果。

2. 如何集成JWT

为了集成JWT,你需要做以下几个步骤:

2.1 添加依赖

你需要在pom.xml文件中添加以下依赖:

<!-- JWT依赖 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.10.7</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.10.7</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.10.7</version>
    <scope>runtime</scope>
</dependency>

2.2 实现JWT工具类

接下来,你需要实现一个工具类,用于生成JWT Token和解析JWT Token。参考代码如下:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

@Component
public class JwtTokenUtil {

    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 根据用户信息生成Token
     * @param username 用户名
     * @return
     */
    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, username);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 解析Token,获取用户信息
     * @param token
     * @return
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证Token是否有效
     * @param token
     * @param username
     * @return
     */
    public boolean validateToken(String token, String username) {
        String usernameFromToken = getUsernameFromToken(token);
        return usernameFromToken.equals(username) && !isTokenExpired(token);
    }

    /**
     * 判断Token是否已过期
     * @param token
     * @return
     */
    private boolean isTokenExpired(String token) {
        Date expirationDate = getExpirationDateFromToken(token);
        return expirationDate.before(new Date());
    }

    /**
     * 从Token中获取过期时间
     * @param token
     * @return
     */
    private Date getExpirationDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据Token获取Claims信息
     * @param token
     * @return
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    /**
     * 根据Token生成过期时间
     * @return
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

}

这里我们使用了@Component注解将JwtTokenUtil类标记为Spring组件,以便在其他组件中自动注入该类的实例。需要注意的是,你需要在application.properties文件中配置jwt.secret和jwt.expiration两个参数。

2.3 实现认证接口

你需要实现一个认证接口,用于用户登录。该接口将会根据用户名和密码生成对应的JWT Token,并返回给前端。

import com.example.demo.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 用户登录认证
     * @param authenticationRequest
     * @return
     */
    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody AuthenticationRequest authenticationRequest) {
        String username = authenticationRequest.getUsername();
        String password = authenticationRequest.getPassword();
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        String token = jwtTokenUtil.generateToken(username);
        return ResponseEntity.ok(new AuthenticationResponse(token));
    }

}

这里我们使用@RestController注解将AuthController类标记为Spring MVC的控制器,并使用@RequestMapping注解指定了该Controller的基础路由,即/auth。需要注意的是,这里我们还使用了@Autowired注解将AuthenticationManager、UserDetailsService、JwtTokenUtil、PasswordEncoder四个类自动注入到AuthController类中,以便我们可以直接使用它们的实例。

2.4 实现JWT过滤器

你需要实现一个JWT过滤器,用于在请求中验证JWT Token的合法性并鉴权。参考代码如下:

import com.example.demo.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    /**
     * JWT过滤器逻辑
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String authToken = authHeader.substring("Bearer ".length());
            String username = jwtTokenUtil.getUsernameFromToken(authToken);
            if (username != null && jwtTokenUtil.validateToken(authToken, username)) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } else {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.getWriter().write("Token invalid or expired!");
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

}

这里我们使用了@Component注解将JwtAuthenticationTokenFilter类标记为Spring组件,以便在其他组件中自动注入该类的实例。

2.5 配置Spring Security

最后,你需要为Spring Security添加以下配置:

import com.example.demo.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

这里我们使用了@Configuration、@EnableWebSecurity、@EnableGlobalMethodSecurity注解将SecurityConfig类标记为Spring Security的配置类,并使用了@Bean注解将PasswordEncoder、DaoAuthenticationProvider、AuthenticationManager三个组件标记为Spring组件,以便在其他组件中自动注入它们的实例。

3. 示例说明

下面是两个例子,以说明如何使用本文中的代码实现前后端的认证功能。

3.1 登录认证

前端发送POST请求到http://localhost:8080/auth/login,请求体包含用户名和密码,后端返回JWT Token。参考代码如下:

$.ajax({
    type: "POST",
    url: "/auth/login",
    data: JSON.stringify({
        "username": "username",
        "password": "password"
    }),
    dataType: "json",
    contentType: "application/json",
    success: function (response) {
        var token = response.token;
    },
    error: function (response) {
        // 处理错误
    }
})

3.2 请求鉴权

前端发送带有JWT Token的请求到后端,后端通过JWT过滤器对Token进行验证,并进行鉴权。参考代码如下:

$.ajax({
    type: "GET",
    url: "/api",
    headers: {
        "Authorization": "Bearer " + token
    },
    success: function (response) {
        // 处理响应
    },
    error: function (response) {
        // 处理错误
    }
})

4. 结语

通过本文的讲解,你已经了解了如何集成JWT来实现前后端的认证功能,并且实现了一个完整的示例代码。需要注意的是,本文代码的示例只是一种可能的实现方式,你可以根据你的实际需求和技术背景进行优化和改进。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Boot 集成JWT实现前后端认证的示例代码 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • java实现简单猜拳小游戏

    Java实现简单猜拳小游戏攻略 本文旨在介绍如何使用Java语言实现一个简单的猜拳小游戏。在本文中,我们将涉及如何实现游戏逻辑,如何获取用户输入以及如何进行游戏界面的展示。接下来将详细介绍这些内容。 实现游戏逻辑 在猜拳游戏中,玩家与计算机进行猜拳比赛并决定胜负。为了实现这个过程,我们可以使用Java中的随机数来模拟计算机的猜拳选择,并根据玩家选择和计算机选…

    Java 2023年5月19日
    00
  • JS结合bootstrap实现基本的增删改查功能

    让我来给你讲一下如何使用JS结合Bootstrap实现基本的增删改查功能的完整攻略。我们将通过两个示例来讲解。 示例一-学生管理系统 一、准备工作 1.首先需要在我们的HTML文件中引用Bootstrap和jQuery库。这可以通过以下代码进行实现: <link rel="stylesheet" href="https:/…

    Java 2023年6月15日
    00
  • Java基础-Java编程语言发展史

    Java基础-Java编程语言发展史 Java的起源 Java是一种由Sun Microsystems公司于1995年推出的面向对象编程语言。最初,Sun公司希望开发一种嵌入式系统的语言,但是随着互联网的发展,Java被扩展为可以运行在任意平台上的通用编程语言。Java的诞生,极大地简化了跨平台应用程序的开发,也促进了互联网的发展。 Java的版本历史 Ja…

    Java 2023年5月23日
    00
  • Java+swing实现抖音上的表白程序详解

    Java+Swing实现抖音上的表白程序详解 介绍 本文介绍如何使用Java语言和Swing库实现一个类似于抖音表白程序的小程序。本文会对如何使用Java和Swing实现图形用户界面进行详细讲解,并提供代码示例,帮助初学者了解Java和Swing图形用户界面开发的基础知识。 准备工作 在开始之前,确保你已经安装好了Java开发环境和Swing库。如果尚未安装…

    Java 2023年5月19日
    00
  • Idea开发工具之SpringBoot整合JSP的过程

    接下来我会详细讲解在Idea开发工具中如何整合SpringBoot和JSP。 准备工作 在开始之前,确保你已经完成以下准备工作: 安装了JDK和Idea开发工具。 创建一个SpringBoot项目。 确保pom.xml中已经添加了对于Spring Web和Tomcat的依赖。 整合JSP 第一步:在pom.xml中添加依赖 在pom.xml中添加以下依赖: …

    Java 2023年6月15日
    00
  • Java如何实现简单的RPC框架

    RPC(Remote Procedure Call)是一种面向服务的RPC(Remote Procedure Call)请求响应协议。 Java提供了众多实现RPC框架的库,其中比较著名的有Dubbo、Thrift、 gRPC等。下面我们以Dubbo框架为例,详细讲解Java如何实现简单的RPC框架。 1. Dubbo框架简介 Dubbo是一个RPC框架,支…

    Java 2023年5月18日
    00
  • SpringBoot @PostConstruct原理用法解析

    针对“SpringBoot@PostConstruct原理用法解析”这一话题,我将给出完整的攻略。我们将从以下几个方面来讲解: @PostConstruct注解是什么? @PostConstruct注解的作用 @PostConstruct注解的用法 @PostConstruct的示例 小结 1. @PostConstruct注解是什么? @PostConst…

    Java 2023年5月15日
    00
  • 使用BindingResult 自定义错误信息

    下面是关于使用BindingResult自定义错误信息的完整攻略。 一、BindingResult简介 在Spring MVC框架中,接受前端数据的方法一般会使用@ModelAttribute或@RequestBody注解对参数进行声明,此时也可以添加BindingResult类型的参数,用于接收数据绑定时产生的错误信息。 BindingResult是Spr…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部