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 2023年5月26日
    00
  • Java线程等待用法实例分析

    Java线程等待用法实例分析 在Java编程中,线程等待是掌握多线程知识的重要一环。当在某些情况下需要进行线程同步、控制程序执行顺序时,常常需要使用线程等待。本文将详细讲解Java线程等待的用法,并通过两个实例对其进行示例说明。 等待与通知 在线程中,等待与通知是两个相互关联的概念。等待指的是线程暂停自身的执行,并且进入等待状态,等待系统发出通知,来唤醒其继…

    Java 2023年5月18日
    00
  • Java之使用POI教你玩转Excel导入与导出

    Java之使用POI教你玩转Excel导入与导出 什么是POI POI是一个Java开发的用于操作Microsoft Office格式文件的开源框架。POI可以读写文档、演示文稿、Excel文件等,并且支持多种文件格式。下面我们主要讲解POI在Java中如何操作Excel文件的导入与导出。 Excel文件的导入 准备工作 首先,我们需要在pom.xml文件中…

    Java 2023年5月19日
    00
  • 解析SpringSecurity+JWT认证流程实现

    下面我将为大家详细讲解 “解析SpringSecurity+JWT认证流程实现” 的完整攻略。 1. JWT简介 JSON Web Token(JWT)是一种定义了一种紧凑且自包含的方式,可以用于将各种信息传递给另一个系统。JWT 在 Web 应用中得到广泛的应用,其最大的优势就是可以在客户端和服务器之间,通过方式方便快捷的的方式实现身份认证和授权。 JWT…

    Java 2023年5月20日
    00
  • springcloud-gateway集成knife4j的示例详解

    下面是关于“springcloud-gateway集成knife4j的示例详解”的攻略: 1. 准备工作 在Spring Boot项目中添加以下依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-clo…

    Java 2023年5月31日
    00
  • 基于Java protected的深入理解

    基于Java protected的深入理解 在Java中,protected是一种访问修饰符,它的作用是控制类的成员变量和成员方法的访问范围。在本文中,我们将探讨protected修饰符的具体用法和相关知识点。 protected修饰符的作用 protected修饰符可以使得一个类的成员变量和成员方法在该类的子类和同一包中的其他类中访问。同时,它也可以保证该…

    Java 2023年5月26日
    00
  • jquery实现联想词搜索框和搜索结果分页的示例

    首先,需要明确的是,jQuery 是一个 JavaScript 函数库,其目的是使JavaScript的使用更容易,简洁。使用 jQuery 可以帮助我们更快捷地编写出与原生 JavaScript 相同的功能。 要实现一个联想词搜索框和搜索结果分页,大致可以分为以下几个步骤: 1. 设计 UI 首先,我们需要设计一下我们的页面 UI,包括搜索框、搜索结果展示…

    Java 2023年6月15日
    00
  • JavaWeb动态导出Excel可弹出下载

    引言: 在JavaWeb开发过程中,有时候需要将数据库中的数据导出为Excel文件,然后让用户可以进行下载。而且,下载的过程中需要提供一些提示信息,如下载进度、下载成功等信息。本文将详细介绍如何使用JavaWeb动态导出Excel并实现弹出下载的效果。 步骤: 1.创建Excel文件 我们可以使用Apache POI来创建Excel文件,这里就不过多介绍了,…

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