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日

相关文章

  • JSP中通过Servlet 将服务器硬盘图片并展示到浏览器

    在JSP中通过Servlet展示服务器硬盘上的图片,可以按照以下步骤来实现: 在web.xml文件中配置servlet 在web.xml文件中配置servlet,将servlet的访问路径配置为“/image”,并将servlet的类名配置为“com.example.ImageServlet”。 示例代码: <servlet> <servl…

    Java 2023年6月15日
    00
  • 在IDEA中搭建最小可用SpringMVC项目(纯Java配置)

    以下是关于“在IDEA中搭建最小可用SpringMVC项目(纯Java配置)”的完整攻略,其中包含两个示例。 在IDEA中搭建最小可用SpringMVC项目(纯Java配置) Spring MVC是一个基于Java的Web框架,它可以帮我们快速开发Web应用程序。在IDEA中搭建最小可用SpringMVC项目非常简单,本文将介绍如何使用纯Java配置搭建最小…

    Java 2023年5月17日
    00
  • Spring Boot 使用 SSE 方式向前端推送数据详解

    Spring Boot 使用 SSE 方式向前端推送数据详解 概述 Server-Sent Events (SSE) 是一种基于 HTTP 协议的服务器推送技术,可以将服务器端的实时数据流推送给客户端,常用于构建实时通讯、监控等场景。Spring Boot 提供了很好的支持,可以方便地将 SSE 技术应用于开发中。 步骤 1. 添加依赖 在 pom.xml …

    Java 2023年6月3日
    00
  • Java集合ArrayList与LinkedList详解

    Java集合ArrayList与LinkedList详解 概述 Java集合分为两大类:Collection和Map。其中Collection又可以分为List、Set和Queue三种。 ArrayList和LinkedList是List接口的两种实现类,它们都可以存储按顺序排列的元素,但是它们之间有一些区别。本文将从以下几个方面详细讲解ArrayList和…

    Java 2023年5月26日
    00
  • 从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate

    下面我将详细讲解“从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate”的完整攻略。 前置要求 在正式进行搭建之前,需要确保你已经安装配置好以下软件: JDK Maven Tomcat IDE(推荐使用IntelliJ IDEA) 步骤一:创建Maven项目 首先,我们需要创建一个Maven项目。在IDE中,找到创建M…

    Java 2023年5月20日
    00
  • Java反射机制基础详解

    Java反射机制基础详解 Java反射机制是指在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法,在运行时刻可以调用任意一个方法或者访问任意一个属性,这种方法称之为反射机制。 反射机制主要涉及三个类:Class,Constructor和Method。 Class类 在Java反射机制中,Class是反射机制的根源,它代表了被加载进内存中的类。Cla…

    Java 2023年5月20日
    00
  • springboot整合EHCache的实践方案

    下面就是“springboot整合EHCache的实践方案”的完整攻略,过程中将会包含两条实例: 1. 添加依赖 首先,在pom.xml文件中添加如下依赖: <dependencies> <!– Spring Boot 依赖 –> <dependency> <groupId>org.springframew…

    Java 2023年5月20日
    00
  • java统计字符串中重复字符出现次数的方法

    要统计字符串中重复字符的出现次数,可以采用以下的方法: 1. 利用Map统计字符出现次数 首先我们可以定义一个Map来存储每个字符出现的次数,然后遍历字符串中每个字符,并通过Map统计该字符的出现次数。 例如以下的Java代码: public static void countDuplicateChars(String str) { Map<Chara…

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