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日

相关文章

  • 在CentOS 6.3中安装与配置Tomcat-7方法

    以下是“在CentOS 6.3中安装与配置Tomcat-7方法”的完整攻略: 安装Java 首先,从官网下载Java安装包。在本示例中,我们将操作JDK 8版本: wget –no-check-certificate –no-cookies –header "Cookie: oraclelicense=accept-securebackup-…

    Java 2023年5月19日
    00
  • Spring Boot Admin实现服务健康预警功能

    Spring Boot Admin是一个开源的监控和管理Spring Boot应用程序的工具。它提供了一个Web界面,可以方便地查看应用程序的健康状况、性能指标和日志信息。以下是Spring Boot Admin实现服务健康预警功能的完整攻略: 添加依赖 在Spring Boot应用程序中,我们需要添加spring-boot-starter-actuator…

    Java 2023年5月15日
    00
  • Java获取一维数组的最小值实现方法

    当需要获取一维数组中最小值时,Java提供了多种实现方法,本文将对这些方法进行详细讲解。 方法一:使用for循环进行遍历 此方法是最基本的实现方式,在遍历整个数组的过程中,用一个临时变量记录最小值,并不断更新该变量,最终得到整个数组中的最小值。 示例代码: public int getMinValue(int[] arr) { int min = arr[0…

    Java 2023年5月26日
    00
  • SpringBoot整合JPA方法及配置解析

    关于SpringBoot整合JPA方法及配置解析的完整攻略,我给你详细讲解一下。 什么是JPA JPA(Java Persistence API)是Sun为JavaEE开发量身定制的一套API,用于处理对象与关系数据库的映射(Object Relational Mapping)问题。 通过JPA,我们可以使用Java类和对象来操作关系型数据库,而不需要写直接…

    Java 2023年5月20日
    00
  • c# 制作gif的四种方法

    C# 制作 Gif 的四种方法 1. 使用Gifski库制作Gif Gifski是一个基于 Rust 编写的 Gif 压缩库,可以生成高质量的 Gif 图像。在 C# 中,可以通过调用 Gifski 的 DLL 文件来实现 Gif 图像的制作。 以下是使用 Gifski 制作 Gif 图像的示例: using GifskiLib; // 创建 Gifski …

    Java 2023年5月19日
    00
  • Java获取时间年、月、日的方法

    下面是详细讲解 Java 获取时间年、月、日的方法的攻略。 获取当前时间 Java 中获取当前时间的方法有很多种,下面介绍两种比较常见的方法: 方法一:使用 Date 类 可以使用 Java 中的 Date 类来获取当前时间,代码如下: import java.util.Date; public class GetCurrentTimeDemo { publ…

    Java 2023年5月20日
    00
  • java实现简单图书管理系统

    Java实现简单图书管理系统完整攻略 背景介绍 随着数字化时代的来临,人们倾向于利用计算机来管理综合信息。图书管理系统是一种管理图书库存、记录图书信息、查询图书信息、借阅和交还图书等方面的软件系统,它可以帮助图书馆实现书籍信息的自动化处理和管理。Java语言是一种优秀的编程语言,其特点包括跨平台性、面向对象、易学易用等,适合开发这种类型的系统。 系统架构 简…

    Java 2023年5月18日
    00
  • Java如何使用elasticsearch进行模糊查询

    下面是关于Java如何使用elasticsearch进行模糊查询的完整攻略。 准备工作 为了使用elasticsearch的模糊查询功能,我们需要先安装elasticsearch,然后使用Java API连接elasticsearch。这里以elasticsearch 7.15.1版本为例。 安装elasticsearch elasticsearch的安装过…

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