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日

相关文章

  • Java8 日期和时间类的基本使用

    Java8 日期和时间类的基本使用攻略 Java8引入了全新的日期和时间API,这个API提供了一些非常有用和强大的类和方法,它们用于处理日期、时间、时间间隔以及处理时区等问题。本文将详细介绍Java8日期和时间API的基本使用方法和示例。 Java8日期类 Java8日期类主要分为三种类型: LocalDate:处理日期 LocalTime:处理时间 Lo…

    Java 2023年5月20日
    00
  • 深入解析Java类加载的案例与实战教程

    深入解析Java类加载的案例与实战教程 1. Java类加载器的概述 JVM在执行Java程序时,会将Java代码编译成字节码文件,字节码文件称为.class文件,然后通过类加载器将字节码文件加载到JVM中进行运行。Java类加载器负责查找并加载字节码文件,并根据字节码文件创建类的定义。 Java类加载器根据加载位置分为三类: Bootstrap Class…

    Java 2023年6月15日
    00
  • Java实现局域网IP地址扫描

    下面我将详细讲解 Java 实现局域网 IP 地址扫描的完整攻略。这里将会分为以下几个步骤: 获取本机的 IP 地址 用正则表达式获取 IP 地址前缀 遍历 IP 地址前缀下的所有 IP 地址 发送 ICMP 包测试 IP 地址是否存活 下面分别进行讲解。 获取本机的 IP 地址 在 Java 中,我们可以通过调用 InetAddress.getLocalH…

    Java 2023年5月26日
    00
  • 使用Spring boot标记一个方法过时

    使用Spring Boot标记一个方法过时,可以通过@Deprecated注解来实现。@Deprecated注解用于标记某个类、属性或方法已过时或不推荐使用,并提示使用者使用新的替代方案来代替。 下面是使用Spring Boot标记方法过时的示例: 示例一: @Deprecated public void oldMethod() { // 这个方法已过时,不…

    Java 2023年5月19日
    00
  • Eclipse怎么快速开发jni程序?

    Eclipse怎么快速开发jni程序? 1. 什么是jni? Java本地接口(Java Native Interface,JNI)是一个桥接库,可以让Java虚拟机(JVM)调用本地代码。JVM本身是由C / C ++编写的,因此JNI为Java程序员提供了调用C / C ++库中函数的能力,同时也为C / C ++程序员提供了将代码与Java应用程序集成…

    Java 2023年5月26日
    00
  • ES6知识点整理之模块化的应用详解

    关于“ES6知识点整理之模块化的应用详解”的完整攻略,以下是我的分享: 1. 概述 在ES6中,我们可以使用模块化来组织和管理代码,这也是ES6语法中比较重要的一个知识点。通过模块化,我们可以把一个大文件拆分成多个小文件,每个小文件只负责一个特定的功能,这样既方便代码的维护,也提高了代码的可读性和可复用性。 2. 模块化的基础语法 在ES6中,可以使用imp…

    Java 2023年5月26日
    00
  • idea2020最新版配置maven的方法

    下面我将为你讲解“idea2020最新版配置maven的方法”的完整攻略,步骤如下: 1. 下载maven 在官网 https://maven.apache.org/download.cgi 下载maven的最新版本,解压到本地任意文件夹。 2. 配置环境变量 在系统环境变量中新建一个变量MAVEN_HOME,并设置为maven解压目录的路径(如C:\apa…

    Java 2023年5月20日
    00
  • Java实现宠物商店管理系统

    Java实现宠物商店管理系统完整攻略 1. 需求分析 首先,我们需要明确商店管理系统所具备的功能,包括但不限于以下几个方面: 宠物信息管理 宠物类别管理 宠物销售管理 宠物库存管理 宠物订单管理 2. 系统设计 基于需求,我们可以设计出宠物商店管理系统的基本架构,其中包括以下几个模块: 宠物信息管理模块 宠物类别管理模块 宠物销售管理模块 宠物库存管理模块 …

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