SpringBoot SpringSecurity JWT实现系统安全策略详解

SpringBoot SpringSecurity JWT实现系统安全策略详解

1. 什么是JWT

JWT(JSON Web Token)是一种用于认证的开放标准。可以基于HTTP协议上的Bearer认证方式对用户进行身份验证和授权。JWT由三部分组成:头部、载荷以及签名。

头部:包含了加密算法、哪种类型的token(例如,Bearer),可以使用什么类型的算法来进行加密等信息。

载荷:是存放有效信息的地方,可以自定义信息字段,例如用户id、登陆时间、有效期等。

签名:是第三段,主要用来验证上面两部分的合法性,保证信息不会被篡改。

2. 为何选择SpringBoot SpringSecurity JWT

SpringBoot是一个非常流行的Java Web开发框架,通过SpringBoot开发一个Web应用非常容易、便捷、高效。

而SpringSecurity是Spring提供的一个安全框架,它实现了许多常用的安全功能,如权限设置、身份认证等,使用SpringSecurity能为应用程序提供安全支持,保证应用程序的安全性。

使用JWT认证,能够实现无状态的验证,不需要在服务器端保存Session,有效攻击防御XSS、CSRF、SQL Injection等常见的攻击。

3. JWT实现系统安全策略步骤

  1. 引入SpringBoot、SpringSecurity和JWT依赖

在使用SpringBoot开发一个应用程序时,可以添加对应的依赖来简化操作。首先在pom.xml 中添加以下依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
  1. 对JWT进行配置

首先要定义一个类,用于封装加密JWT时需要的信息,包括JWT的发行人、主题等。如下:

@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtConfig {

    // key
    private String key;

    // 过期时间,单位:秒。默认2小时
    private long expire = 7200;

    // header字段
    private String header = "Authorization";

    // token 前缀
    private String prefix = "Bearer ";

    // 获取 JWT 签发者
    private String issuer;

    // 获取指定的声明
    private Map<String, Object> claims = new HashMap<>();
    // getter setter 设置默认值
}

主要考虑到了:

  • key 就是 JWT 的密钥
  • expire 是 JWT 的有效期,单位是 秒
  • header 是将 JWT 存储在 HTTP 请求中时的 key
  • prefix 是 JWT 存储时,前缀字符串
  • issuer 表示 JWT 签发者
  • claims 表示 JWT 自身声明信息

  • 在 Spring Security 配置类中添加 JWT

首先编写一个获取用户ID的方法public String getCurrentUserId() { ... },根据当前的 Authentication 对象获取当前用户 ID。

编写完毕后,我们就可以在 Spring Security 配置类中使用JWT了。如下:

@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtConfig jwtConfig;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

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

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(jwtUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public AuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new AuthenticationTokenFilter(jwtConfig, jwtUserDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();

        // 允许访问的接口
        http.authorizeRequests()
                .antMatchers(
                        "/swagger-ui.html",
                        "/swagger-resources/**",
                        "/v2/api-docs",
                        "/auth/**"
                )
                .permitAll();

        http.authorizeRequests().anyRequest().authenticated();

        // 定义登录页和默认跳转路径
        http.formLogin().loginPage("/auth/login").defaultSuccessURL("/").permitAll();

        // 定义登出操作
        http.logout().logoutUrl("/auth/logout").permitAll()
                .logoutSuccessUrl("/auth/login");

        // 添加JWT过滤器
        http.addFilterBefore(authenticationTokenFilterBean(),
                UsernamePasswordAuthenticationFilter.class);
    }
}
  1. 使用JWT进行用户认证

在登录接口中,用户需要提供用户名和密码,系统通过加密之后获得JWT的Token,然后返回给客户端。客户端访问服务器的其他接口时,将Token作为Authorization字段加入HTTP请求头中传递给服务器。

如果JWT验证成功,则说明用户已经登陆了,可以访问需要登陆才能访问的API了。例如:

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/hello")
    @PreAuthorize("hasRole('USER')")
    public String hello() {
        return "Hello, JWT!";
    }
}

4. 示例说明

示例1:通过JWT认证需要用户登录后才能获取的资料

  1. 登录
POST:/auth/login
BODY:
{
    "username": "test",
    "password": "123456"
}

返回:

{
    "code": 200,
    "msg": "登录成功",
    "data": {
        "id": 1,
        "username" : "test",
        "token": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTExMTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw"
    }
}

  1. 获取需要认证才能访问的资源
GET:/api/hello
Header:
   Authorization:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTEwOTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw

返回:

{
    "code": 200,
    "msg": "请求成功",
    "data": "Hello, JWT!"
}

示例2:使用JWT实现文件上传接口的安全

  1. 登录
POST:/auth/login
BODY:
{
    "username": "test",
    "password": "123456"
}

返回:

{
    "code": 200,
    "msg": "登录成功",
    "data": {
        "id": 1,
        "username": "test",
        "token": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTEwOTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw"
    }
}

  1. 上传文件
POST:/api/file/upload
Header:
   Authorization:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTEwOTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw

BODY:
{
    "file": "Base64文件字符串"
}

返回:

{
    "code": 200,
    "msg": "请求成功",
    "data": "文件上传成功"
}

以上就是使用SpringBoot、SpringSecurity和JWT实现系统安全策略的详细攻略,具体实现方法可以参考示例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot SpringSecurity JWT实现系统安全策略详解 - Python技术站

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

相关文章

  • 基于json解析神器 jsonpath的使用说明

    下面是基于Json解析神器JsonPath的使用说明的详细攻略。 什么是JsonPath? JsonPath是一个基于Java的Json解析库,它可以用于解析Json数据并提取其中的内容。JsonPath使用类似XPath的查询语法,并支持大部分XPath表达式,同时还有一些自己的表达式。 如何使用JsonPath 步骤一:引入依赖 要使用JsonPath,…

    Java 2023年5月26日
    00
  • Swagger2不被SpringSecurity框架拦截的配置及说明

    配置Swagger2不被SpringSecurity框架拦截的方法 在SpringBoot项目中,只需要在WebSecurityConfigurerAdapter的configure方法中配置放行Swagger的路径即可。示例代码如下: @Configuration @EnableWebSecurity public class SecurityConfig…

    Java 2023年5月20日
    00
  • Java C++ 算法leetcode828统计子串中唯一字符乘法原理

    Java C++ 算法leetcode828统计子串中唯一字符乘法原理 题目描述 给定一个字符串,你需要统计其中唯一字符的个数。 具体地,你需要统计所有的出现恰好一次的字符的个数。 示例 输入: “ABCDEF”输出: 6解释: 出现一次的字符有 ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’,因此唯一字符的个数为 6。 输入: “ABCDEFAB…

    Java 2023年5月19日
    00
  • spring结合struts的代码详解

    下面我来详细讲解“spring结合struts的代码详解”的完整攻略。 一、结合Spring和Struts的优势 使用Spring结合Struts开发Web应用程序,最主要的优点就是能够将Struts的ActionBean实例管理交由Spring容器,使得我们能够在ActionBean中自动注入Spring容器中的Bean,从而更加方便和灵活地开发Web应用…

    Java 2023年5月20日
    00
  • Java中数据库常用的两把锁之乐观锁和悲观锁

    Java中数据库常用的两把锁是乐观锁和悲观锁。 什么是乐观锁和悲观锁? 悲观锁 悲观锁假定在执行操作时会产生并发冲突,因此在操作数据前先加锁,确保操作数据时不会被其他人修改。悲观锁的典型实现就是数据库中的行锁、表锁。 在Java中,悲观锁常用的实现就是synchronized关键字和ReentrantLock类。 乐观锁 乐观锁假定在执行操作时不会产生并发冲…

    Java 2023年5月19日
    00
  • 什么是Java内存模型?

    Java内存模型是一个规定了线程之间如何通过内存进行通讯的规范。JMM(Java Memory Model)规定了Java虚拟机如何控制线程与内存之间的数据传输。JMM主要通过定义内存栅栏和Happens-Before规则来实现线程通信。 JMM内存栅栏 内存栅栏是指一种同步屏障,用于强制共享数据的可见性和顺序性,确保各线程对内存所读到的数据是一致的。 Lo…

    Java 2023年5月11日
    00
  • 浅谈java中六大时间类的使用和区别

    浅谈Java中六大时间类的使用和区别 Java中提供了六种对时间进行处理的类:Date、Calendar、SimpleDateFormat、DateFormat、Duration和Instant。这些类都各自有着不同的用法和适用场景。在本文中,我们将详细讨论这些类的区别和用法。 Date类 Date类是Java中处理日期和时间的最基本的类,它提供了一系列方法…

    Java 2023年6月1日
    00
  • 使用JAVA通过ARP欺骗类似P2P终结者实现数据封包监听

    首先需要明确的是,ARP欺骗是指通过伪造ARP响应的方式,诱导受害者将数据包发送至攻击者的电脑,从而实现数据封包监听、拦截等攻击行为。下面给出使用Java实现ARP欺骗的攻略过程。 1. 获取受害者电脑的MAC地址 要实现ARP欺骗的攻击,首先需要获取受害者电脑的MAC地址。可以通过以下代码实现: InetAddress address = InetAddr…

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