Spring Security结合JWT的方法教程

我来详细讲解一下“Spring Security结合JWT的方法教程”的完整攻略。

1. 什么是Spring Security和JWT

Spring Security是一种基于框架的安全性解决方案,它为Java应用程序提供了身份验证和身份验证授权功能。

JWT(JSON Web Token)是一种身份验证和授权的标准,它将声明和签名打包在一个安全令牌中。JWT不需要在服务器上保存会话状态,它可以让你的服务器成为无状态的。

结合Spring Security和JWT可以构建一个安全而高效的后端系统,本文将介绍如何实现这一目标。

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

2.1 添加Spring Security和JWT依赖

首先,需要将Spring Security和JWT依赖添加到项目中。在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.7.0</version>
</dependency>

2.2 实现用户认证

接下来,需要实现用户认证功能。具体来说,这个功能应该包括一个实现UserDetailsService接口的类(用于从数据库或其他持久化存储中获取用户信息)和一个实现AuthenticationProvider接口的类(用于验证用户提供的登录凭据)。在实现完这两个类之后,需要将它们添加到Spring的安全配置中。

示例代码:

MyUserDetailsService.java

@Service
public class MyUserDetailsService implements UserDetailsService {
    private final UserService userService;
    public MyUserDetailsService(UserService userService) {
        this.userService = userService;
    }
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.getUserByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found"));
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
    }
}

MyAuthenticationProvider.java

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
    private final MyUserDetailsService userDetailsService;
    private final PasswordEncoder passwordEncoder;
    public MyAuthenticationProvider(MyUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
    }
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getPrincipal().toString();
        String password = authentication.getCredentials().toString();
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            throw new BadCredentialsException("Invalid credentials");
        }
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
        token.setDetails(userDetails);
        return token;
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

WebSecurityConfigurerAdapter的子类中添加这两个类:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final MyUserDetailsService userDetailsService;
    private final MyAuthenticationProvider authenticationProvider;
    public SecurityConfig(MyUserDetailsService userDetailsService, MyAuthenticationProvider authenticationProvider) {
        this.userDetailsService = userDetailsService;
        this.authenticationProvider = authenticationProvider;
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        auth.authenticationProvider(authenticationProvider);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // ...
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

2.3 实现JWT功能

接下来需要实现JWT功能。具体而言,需要实现一个能够生成JWT token的方法和一个能够验证token并从其中提取用户信息的方法。

示例代码:

JwtUtil.java

@Component
public class JwtUtil {
    private static final String SECRET_KEY = "mySecretKey";
    private static final int TOKEN_EXPIRATION = 1800;
    public String generateToken(User user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", user.getUsername());
        claims.put("roles", user.getRoles());
        Date now = new Date();
        Date expiration = new Date(now.getTime() + TOKEN_EXPIRATION * 1000L);
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(expiration)
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }
    public Optional<User> getUserFromToken(String token) {
        try {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            String username = claimsJws.getBody().get("username", String.class);
            @SuppressWarnings("unchecked")
            List<String> roles = claimsJws.getBody().get("roles", List.class);
            User user = new User();
            user.setUsername(username);
            user.setRoles(roles);
            return Optional.of(user);
        } catch (JwtException e) {
            return Optional.empty();
        }
    }
}

2.4 配置Spring Security以适应JWT

最后,只需要为Spring Security添加配置来包含JWT功能即可。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final MyUserDetailsService userDetailsService;
    private final MyAuthenticationProvider authenticationProvider;
    private final JwtUtil jwtUtil;
    public SecurityConfig(MyUserDetailsService userDetailsService, MyAuthenticationProvider authenticationProvider, JwtUtil jwtUtil) {
        this.userDetailsService = userDetailsService;
        this.authenticationProvider = authenticationProvider;
        this.jwtUtil = jwtUtil;
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        auth.authenticationProvider(authenticationProvider);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/authenticate").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

3. 示例

下面将简单介绍两个使用JWT的示例。

3.1 用户登录和获取用户信息

前端向后端发送请求,使用JWT进行用户登录验证,并获取当前用户信息。

authenticate请求实现用户登录,user-data请求获取用户信息。在响应中,后端将返回一个包含当前用户信息的JWT token,前端在使用user-data请求时,带上此token,从而验证用户身份,并获取用户信息。

后端实现:

@RestController
@RequestMapping("/api")
public class UserController {
    private final MyUserDetailsService userDetailsService;
    private final JwtUtil jwtUtil;
    public UserController(MyUserDetailsService userDetailsService, JwtUtil jwtUtil) {
        this.userDetailsService = userDetailsService;
        this.jwtUtil = jwtUtil;
    }
    @PostMapping("/authenticate")
    public ResponseEntity<?> authenticate(@RequestBody LoginRequest loginRequest) {
        try {
            Authentication authentication = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
            authentication = new MyAuthenticationProvider(userDetailsService, passwordEncoder()).authenticate(authentication);
            UserDetails userDetails = (UserDetails) authentication.getDetails();
            String token = jwtUtil.generateToken(userService.getUserByUsername(loginRequest.getUsername()));
            return ResponseEntity.ok(new JwtResponse(token));
        } catch (BadCredentialsException e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
    }
    @GetMapping("/user-data")
    public ResponseEntity<?> getUserData(HttpServletRequest request) {
        Optional<User> user = Optional.empty();
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            user = jwtUtil.getUserFromToken(token);
        }
        return user.map(ResponseEntity::ok).orElse(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
    }
}

前端实现:

const login = (username, password) => {
  return axios.post('/api/authenticate', {
    username, password
  }).then(response => {
    const token = response.data.token;
    localStorage.setItem('token', token);
    axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
  }).catch(error => {
    console.log(error);
  });
};
const getUserData = () => {
  return axios.get('/api/user-data').then(response => {
    return response.data;
  }).catch(error => {
    console.log(error);
  });
};

3.2 通过JWT进行API调用的身份验证

前端使用JWT token以请求头的形式向后端API发起请求。

后端实现:

@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/test")
    public ResponseEntity<?> test(@RequestHeader("Authorization") String authHeader) {
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            Optional<User> user = jwtUtil.getUserFromToken(token);
            // do something with user
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }
}

前端实现:

const testApi = () => {
  const token = localStorage.getItem('token');
  return axios.get('/api/test', {
    headers: {
      Authorization: `Bearer ${token}`
    }
  }).then(response => {
    return response.data;
  }).catch(error => {
    console.log(error);
  });
};

好了,以上就是关于Spring Security结合JWT的方法教程的完整攻略。希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security结合JWT的方法教程 - Python技术站

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

相关文章

  • 10中java常见字符串操作实例

    以下是“10种Java常见字符串操作实例”的完整攻略: 简介 字符串是Java中最常用的数据类型之一,几乎所有的Java程序都会涉及字符串的处理。本文主要介绍Java中常见的字符串操作方法。 10种Java常见字符串操作实例 1. 字符串的比较 比较两个字符串是否相等,可以使用equals()方法。 示例1: String str1 = "Hell…

    Java 2023年5月26日
    00
  • SpringBoot Security密码加盐实例

    下面是关于 “SpringBoot Security密码加盐实例” 的详细攻略。 介绍 Spring Security 是一个强大的身份认证和授权框架,Spring Boot 的集成让我们可以非常方便地搭建安全的应用。但是,如果我们对密码进行单纯的 hash 加密,容易被暴力破解,因此需要加盐(salt)使其更加安全。 盐是在密码加密的时候添加到原始密码中的…

    Java 2023年6月3日
    00
  • IDEA配置Maven的超详细步骤

    请看下面的“IDEA配置Maven的超详细步骤”完整攻略: 步骤1:下载Maven 首先需要在官网上下载Maven,选择自己需要的版本。下载后将其解压到指定的文件夹中。 步骤2:配置Maven环境变量 将Maven解压到的文件夹添加到系统环境变量中,即将解压后的目录进入到 PATH 变量中。 步骤3:配置IDEA 打开IDEA,选择 File > Se…

    Java 2023年6月2日
    00
  • Mybatis之如何拦截慢SQL日志记录

    拦截慢SQL并记录日志是Mybatis中非常有用的一项功能,可以帮助我们快速定位系统中存在的性能瓶颈,本文将详细介绍如何配置Mybatis拦截器实现该功能。 1. Mybatis拦截器介绍 Mybatis拦截器是Mybatis中一个非常重要的组成部分,它可以拦截Mybatis执行过程中的各种方法,包括执行SQL语句、参数设置、结果处理等。Mybatis提供了…

    Java 2023年6月15日
    00
  • Java多线程程序中synchronized修饰方法的使用实例

    下面是Java多线程程序中synchronized修饰方法的使用实例的详细攻略。 什么是多线程和synchronized? 多线程是指在同一时间内,多个线程同时执行,每个线程负责执行其中一部分代码,以达到加速程序运行的目的。 synchronized是Java中实现线程同步的关键字,它可以用来修饰方法或对象。当一个方法或一个对象被synchronized关键…

    Java 2023年5月19日
    00
  • 一篇文章带你详解Spring的概述

    一篇文章带你详解Spring的概述 介绍 Spring 是一个开源的框架,用于构建企业级 Java 应用程序。 它为开发人员提供了丰富的功能,以面向对象的方式轻松构建轻量级、可维护、松耦合以及可扩展的应用程序。Spring 框架基于依赖注入(DI)和面向切面编程(AOP)为核心,简化了企业应用程序的开发。本文将通过介绍 Spring 的基础知识、DI、AOP…

    Java 2023年5月19日
    00
  • SpringBoot实现物品点赞功能

    下面是关于SpringBoot实现物品点赞功能的完整攻略: 前言 物品点赞功能是很常见的网站功能之一。Spring Boot 给我们提供了很好的实现方式,通过本文,你可以学习到 Spring Boot 如何实现物品点赞功能。 实现过程 创建数据库 首先我们需要创建一个数据库来储存点赞信息。数据库需要包含以下两个表: item 表:储存物品信息,包括物品 ID…

    Java 2023年5月23日
    00
  • Spring中@Transactional用法详细介绍

    我来为您详细讲解Spring中@Transactional用法的攻略。 Spring中@Transactional用法详细介绍 一、什么是@Transactional @EnableTransactionManagement注解:开启事务管理器。 @Transactional注解:在类或方法上标记该业务需要事务管理。 二、@Transactional的常用属…

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