Java SpringSecurity+JWT实现登录认证

下面我将为你详细讲解“Java SpringSecurity+JWT实现登录认证”的完整攻略。 首先,让我们一步步来实现一个基于SpringSecurity和JWT的用户登录认证系统。整个实现过程包括三个步骤:

  1. 集成SpringSecurity和JWT
  2. 配置SpringSecurity
  3. 实现登录接口

接下来,我们将分别对这三个步骤进行讲解。

1. 集成SpringSecurity和JWT

我们使用Maven来管理项目依赖,因此需要在pom.xml文件中添加如下两个依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>

上述依赖中,spring-boot-starter-security是SpringSecurity的启动器,jjwt-api是JWT的API。

接下来,我们需要创建一个JWT工具类,用于生成和解析JWT,实现代码如下:

@Component
public class JwtTokenUtil {
    private final String secret = "mySecret";
    private final long expiration = 604800L;

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", username);
        claims.put("created", new Date());
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
            return true;
        } catch (ExpiredJwtException ex) {
            System.out.println("Token已过期");
        } catch (SignatureException ex) {
            System.out.println("Token签名错误");
        } catch (JwtException ex) {
            System.out.println("Token解析错误");
        } catch (Exception ex) {
            System.out.println("其他错误");
        }
        return false;
    }
}

上述代码中,核心的三个方法分别是:generateToken用于生成JWT,getUsernameFromToken用于从JWT中获取用户名,validateToken用于验证JWT是否有效。

2. 配置SpringSecurity

接下来,我们需要配置SpringSecurity,添加一个SecurityConfiguration类,实现代码如下:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}password")
                .roles("USER");
    }

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

上述代码中,我们通过auth.inMemoryAuthentication()方式添加了一个用户,用户名为user,密码为password,角色为USER。configure(HttpSecurity http) 方法用于配置访问规则,我们允许/api/login接口不需要认证,其他接口需要进行认证。sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)方法用于设置Session的创建策略为不创建Session。

3. 实现登录接口

最后,我们需要实现一个/login接口,用于接受用户的用户名和密码,生成JWT,并返回给客户端。实现代码如下:

@RestController
@RequestMapping("/api")
public class LoginController {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {
        Authentication authentication = null;
        try {
            authentication = new UsernamePasswordAuthenticationToken(username, password);
            authentication = authenticationManager().authenticate(authentication);
        } catch (Exception e) {
            return ResponseEntity.ok(new ApiResponse(false, "用户名或密码错误"));
        }
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtTokenUtil.generateToken(username);
        return ResponseEntity.ok(new JwtAuthenticationResponse(token));
    }

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

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

    @Autowired
    private UserDetailsService userDetailsService;
}

上述代码中,我们通过/login接口接受到的用户名和密码,创建一个UsernamePasswordAuthenticationToken对象,并调用authenticationManager().authenticate(authentication)方法进行认证,如果认证成功,则生成JWT,并返回给客户端。

至此,我们就完成了一个基于SpringSecurity和JWT的用户登录认证系统。

下面,我来介绍两条关于该系统的使用示例:

  1. 使用Postman进行登录认证

在Postman中发送如下请求:

URL: http://localhost:8080/api/login
Method: POST
Body: x-www-form-urlencoded
- username: user
- password: password

可以得到如下JSON响应:

{
"token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VyIiwiaWF0IjoxNTkyNTIyNzg5LCJleHAiOjE1OTMxMDcyODl9.pjLckrJZL98QXFJ8UDrD7lmlfvI7GcJBAc5FAwVV-easGnaC1z-cQZ7zk4-tjOq7kQZN5yYBLaX10KjcOjSDcA"
}

可以看到,我们成功地获得了JWT。

  1. 使用SpringBoot集成测试进行登录认证

在创建SpringBoot集成测试时,需要在测试类上添加注解@WebMvcTest,用于启用Spring的Web应用程序上下文,同时会自动配置SpringMvc相依的Bean。

@RunWith(SpringRunner.class)
@WebMvcTest
public class LoginControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private JwtTokenUtil jwtTokenUtil;

    @Test
    public void testLoginSuccess() throws Exception {
        when(jwtTokenUtil.generateToken(any())).thenReturn("test_token");
        String requestBody = "{\"username\":\"user\",\"password\":\"password\"}";
        mockMvc.perform(post("/api/login")
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.token", is("test_token")));
    }

    @Test
    public void testLoginFailure() throws Exception {
        String requestBody = "{\"username\":\"user\",\"password\":\"error_password\"}";
        mockMvc.perform(post("/api/login")
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success", is(false)))
                .andExpect(jsonPath("$.message", is("用户名或密码错误")));
    }
}

上述代码中,我们通过MockMvc对象模拟了一个HTTP请求,发送给/login接口,通过when(jwtTokenUtil.generateToken(any())).thenReturn("test_token")模拟了一个JWT。执行两个测试用例,分别测试了登录成功和登录失败的情况。

希望我的讲解可以帮助到你。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java SpringSecurity+JWT实现登录认证 - Python技术站

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

相关文章

  • 滴滴二面之Kafka如何读写副本消息的

    滴滴二面之Kafka如何读写副本消息的攻略 Kafka 是一种分布式消息系统,消息被分为多个分区存储在多个 broker 中。副本是为了在发生故障时提供消息持久性和可靠性所增加的。在 Kafka 中,每个分区都会有多个副本,其中一个作为主副本,其他副本作为从副本,主副本负责进行读写操作,而从副本只需要对主副本的写操作进行复制,从而保证数据的可靠性。 读副本消…

    Java 2023年5月20日
    00
  • Java中生成二维码

    代码如下: import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.…

    Java 2023年4月18日
    00
  • java BigDecimal精度丢失及常见问分析

    下面是对于“java BigDecimal精度丢失及常见问题分析”的完整攻略。 1. 背景 在Java中进行精确浮点数计算,常常使用BigDecimal类。BigDecimal类有很强的精度和舍入模式控制能力,但是如果不注意使用规范,也会出现与浮点数相似的精度问题:丢失精度。 2. 问题分析 2.1 浮点数精度问题 Java中的浮点数精度问题主要由二进制浮点…

    Java 2023年5月27日
    00
  • 如何解决hibernate一对多注解懒加载失效问题

    下面就来详细讲解如何解决 Hibernate 一对多注解懒加载失效问题。 问题描述 在 Hibernate 中,我们通过一对多的注解来建立两个表的关联关系。如果这个关联关系是懒加载的,那么在查询父表时,子表的数据不会立即被加载,而会在需要使用时再去查询。但是有时候会遇到懒加载失效的问题,这时候就需要解决。下面就是一些常见的解决方法。 解决方法一:使用 Hib…

    Java 2023年5月20日
    00
  • JavaScript处理解析JSON数据过程详解

    下面是“JavaScript处理解析JSON数据过程详解”的完整攻略。 什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于前后端数据传输。它是纯文本的,可读性较好,易于编写和解析,同时支持多种编程语言。 JSON由于其简洁性、标准化、易读性和跨平台性等优点越来越受到广泛的关注和应用。并且许多现代…

    Java 2023年5月26日
    00
  • Java中动态规则的实现方式示例详解

    这篇文章将详细讲解Java中动态规则的实现方式,并且提供两个示例来帮助读者更好地理解此概念。在开始之前,我们来了解一下动态规则的概念。 什么是动态规则 动态规则是指在程序运行时可以动态地修改规则,而无需重新编译代码。这种实现方式增加了程序的灵活性和可维护性,而且不会影响程序的可靠性和性能。 Java中动态规则的实现方式有很多种,下面我们就来看两个示例。 示例…

    Java 2023年5月18日
    00
  • win2003 jsp运行环境架设心得(jdk+tomcat)

    Win2003 JSP运行环境架设心得 (JDK+Tomcat) 完整攻略 简介 本文将介绍在Windows Server 2003操作系统上架设JSP运行环境的过程,其中涉及到JDK和Tomcat的安装、环境配置等内容。教程中会引入两个示例来展示环境搭建的实际应用。 前置知识 在开始操作前,确保您已经掌握以下知识: Windows Server 2003操…

    Java 2023年5月19日
    00
  • Spring MVC结合Spring Data JPA实现按条件查询和分页

    下面是“Spring MVC结合Spring Data JPA实现按条件查询和分页”的完整攻略。 简介 Spring MVC结合Spring Data JPA可以实现按条件查询和分页,这对于实现Web应用程序中的高级搜索和结果分页非常有用。Spring MVC提供了有效的Web层,而Spring Data JPA则提供了持久层,两者结合可以快速搭建一个Web…

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