Spring Security+JWT简述(附源码)

Spring Security是一个强大的安全框架,可以支持高度可定制的身份验证和授权功能。而JWT(JSON Web Token)则是一种轻量级的认证和授权技术,可以在分布式系统中传递和验证用户身份信息。本文将介绍如何结合Spring Security和JWT来实现基于token的身份验证和授权。

1. Spring Security和JWT简介

1.1 Spring Security

Spring Security是一个基于Spring框架的安全框架,提供了全面的身份验证和授权功能。Spring Security可以轻松地与Spring框架集成,提供了一套完整的安全解决方案,可以应用于各种应用场景。

1.2 JWT

JSON Web Token(JWT)是一种轻量级的身份验证和授权技术,可以在分布式系统中传递和验证用户身份信息。JWT由三部分组成:头部(Header)、负载(Payload)和签名(Signature)。头部包含了数据的类型(即JWT),使用的算法等信息;负载包含了要传递的用户信息,例如用户ID、用户名等;签名用来验证数据的完整性,防止数据被篡改。

2. Spring Security和JWT结合实现步骤

2.1 引入依赖

在项目的pom文件中添加如下依赖:

<dependencies>
    <!-- Spring Boot Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Security Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <!-- JWT Starter -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

2.2 实现Spring Security的配置

在配置类中继承WebSecurityConfigurerAdapter,并覆盖configure方法,如下:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/login").permitAll() // 所有用户均可访问的路径
            .anyRequest().authenticated(); // 除上述路径外,所有请求均需身份验证
    }
}

2.3 实现JWT的创建和验证

2.3.1 创建JWT

public class JwtUtil {
    private static final String SECRET_KEY = "mySecretKey";
    private static final long EXPIRATION_TIME = 3600000; // 1 hour
    private static final String TOKEN_PREFIX = "Bearer ";
    private static final String HEADER_STRING = "Authorization";

    public static String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", userDetails.getUsername());
        claims.put("iat", new Date().getTime());

        return Jwts.builder()
            .setClaims(claims)
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
            .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
            .compact();
    }
}

2.3.2 验证JWT

public class JwtUtil {
    ...

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

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

    public static boolean isTokenExpired(String token) {
        Date expiration = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();
        return expiration.before(new Date());
    }
}

2.4 实现登录接口

@RestController
@RequestMapping("/api")
public class LoginController {
    @Autowired
    AuthenticationManager authenticationManager;

    @GetMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            UserDetails userDetails = new User(username, password, new ArrayList<>());
            String jwt = JwtUtil.generateToken(userDetails);
            return jwt;
        } catch (AuthenticationException e) {
            throw new BadCredentialsException("Invalid username/password supplied");
        }
    }
}

2.5 实现需要身份验证的接口

@RestController
@RequestMapping("/api")
public class UserController {
    @GetMapping("/users")
    public List<User> getUsers() {
        return Arrays.asList(
            new User(1L, "Alice"),
            new User(2L, "Bob"),
            new User(3L, "Charlie")
        );
    }

    @GetMapping("/users/{userId}")
    public User getUser(@PathVariable Long userId) {
        return new User(userId, "Alice");
    }
}

以上代码片段中的User类可以自行实现,不再赘述。

2.6 测试

使用Postman或其他Http客户端,访问登录接口,GET请求http://host/api/login,并设置用户名和密码为请求参数。如果身份验证通过,将返回JWT;否则将返回401 Unauthorized。

接下来,访问需要身份验证的接口,例如GET请求http://host/api/users,将JWT添加到请求头Authorization中,格式为“Bearer token”。如果身份验证通过,将返回用户列表;否则将返回401 Unauthorized。

3. 示例

上述步骤已经讲解了如何结合Spring Security和JWT来实现基于token的身份验证和授权。下面将给出另外两个示例来进一步说明其使用方法。

3.1 示例1

本示例实现了一个简单的Spring Boot应用,使用Spring Security和JWT来完成基于token的身份验证和授权。具体代码实现请查看附带源码。

3.2 示例2

本示例实现了一个基于Spring Security和JWT的RESTful API,提供了用户注册、登录和获取用户信息的功能。具体代码实现请查看附带源码。

4. 总结

本文介绍了如何结合Spring Security和JWT来实现基于token的身份验证和授权。首先介绍了Spring Security和JWT的概念和原理,然后详细讲解了如何实现Spring Security和JWT的结合,包括创建和验证JWT、实现登录接口和需要身份验证的接口等。最后,给出了两个示例,供读者参考。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security+JWT简述(附源码) - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Spring Security前后分离校验token的实现方法

    我会详细讲解“Spring Security前后分离校验token的实现方法”的完整攻略。这里将分为以下几个步骤: 获得token 将token保存到请求头中 在后端进行token校验 返回结果给前端 下面我们具体来看一下每一步的实现方法。 1. 获得token 首先,我们需要在前端登录成功之后,获得token。我们可以通过发送登录请求来获取token,例如…

    Java 2023年5月20日
    00
  • Java执行JS脚本工具

    当需要Java程序执行JavaScript脚本时,可以使用Java中的ScriptEngine来实现。 在Java中添加依赖: 首先需要向pom.xml文件中添加JavaScript的依赖。以下是Maven依赖项: <dependency> <groupId>javax.script</groupId> <artif…

    Java 2023年5月26日
    00
  • 浅谈Java基准性能测试之JMH

    浅谈Java基准性能测试之JMH 什么是基准性能测试? 基准性能测试是一种通过对软件或硬件系统进行压力测试来衡量其性能水平的方法。通常,在执行基准性能测试之前,我们需要明确目标,比如检查系统的吞吐量、响应时间和负载下的资源消耗等。 为什么要进行基准性能测试? 在软件开发过程中,我们需要不断地优化代码,以期提高系统的性能和可靠性。而基准性能测试为我们提供了一种…

    Java 2023年5月26日
    00
  • php的curl封装类用法实例

    以下是关于“php的curl封装类用法实例”的完整攻略。 什么是CURL? CURL是一款开源的网络传输工具,它可以模拟客户端和服务端之间的交互,并支持多种网络协议。在PHP中,我们可以通过CURL库来进行网络数据的传输和接收,实现各种网络操作。 封装类如何使用? CURL库提供的API比较复杂,为了更方便使用,我们可以使用PHP中的CURL封装类。以下是封…

    Java 2023年6月16日
    00
  • 在Struts2中如何将父类属性序列化为JSON格式的解决方法

    在Struts2中将父类属性序列化为JSON格式的问题,可以通过使用配置文件和Action的一些属性或方法来解决。以下是实现此目的的两种方法: 方法一:在配置文件中配置json.name和json.includeProperties通过在struts.xml配置文件中使用json.name和json.includeProperties来自定义一个JSON插件…

    Java 2023年5月20日
    00
  • 深入了解Java线程池的原理使用及性能优化

    深入了解Java线程池的原理、使用及性能优化 Java线程池是实现多线程编程的重要机制。它能够有效地控制线程数量,优化资源利用率和性能。本攻略将详细讲解Java线程池的原理、使用和性能优化方法。 线程池原理 线程池是一个线程队列,用于管理和调度线程。它包含一组线程,用于执行任务。线程池中的每个线程都可以从任务队列中获取待执行的任务,并执行它。当一个任务完成,…

    Java 2023年5月19日
    00
  • JavaSpringBoot报错“HttpMessageConversionException”的原因和处理方法

    原因 “HttpMessageConversionException” 错误通常是以下原因引起的: 请求体格式不正确:如果您的请求体格式不正确,则可能会出现此错误。在这种情况下,您需要检查您的请求体格式并确保它们正确。 请求体类型不支持:如果您的请求体类型不支持,则可能会出现此。在这种情况下,您需要检查您的请求体类型并确保它们受支持。 解决办法 以下是解决 …

    Java 2023年5月4日
    00
  • mybatis的Configuration详解

    MyBatis的Configuration详解 MyBatis的Configuration类是整个MyBatis系统的核心,它是用于配置MyBatis系统的重要组件。在本篇攻略中,我们将详细讲解MyBatis的Configuration类。 Configuration类的作用 MyBatis的Configuration类负责读取MyBatis的配置文件,并提…

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