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日

相关文章

  • 深入Ajax代理的Java Servlet的实现详解

    “深入Ajax代理的Java Servlet的实现详解”是一篇介绍如何使用Java Servlet实现Ajax代理的文章。本文一共分为以下几个部分: Ajax代理的概念及作用 Java Servlet的基础知识 使用Java Servlet实现Ajax代理的步骤 示例说明 1. Ajax代理的概念及作用 Ajax代理是一种通过服务器中转Ajax请求的技术。在…

    Java 2023年6月16日
    00
  • Java 程序员掌握 Spring Boot非常有必要

    Java 程序员掌握 Spring Boot 非常有必要 什么是 Spring Boot? Spring Boot 是一个基于 Spring 框架的快速开发框架。它简化了 Spring 应用程序的初始化过程,提供了自动配置选项,使开发人员能够快速构建出基于 Spring 的应用程序。 为什么 Java 程序员掌握 Spring Boot 非常有必要? 提高开…

    Java 2023年5月31日
    00
  • Java Apache POI报错“MissingSheetException”的原因与解决办法

    “MissingCellDataException”是Java的Apache POI类库中的一个异常,通常由以下原因之一引起: 单元格错误:如果单元格中缺少数据,则可能会出现此异常。例如,可能会尝试读取不存在的单元格或尝试读取未填充的单元格。 以下是两个实例: 例1 如果单元格中缺少数据,则可以尝试使用正确的单元格以解决此问题。例如,在Java中,可以使用以…

    Java 2023年5月5日
    00
  • java乐观锁原理与实现案例分析

    Java乐观锁原理与实现案例分析 什么是乐观锁? 乐观锁是一种轻量级锁,它假定不会有其它线程修改共享资源,因此,不需要加锁,只要在最后提交时检查是否有其它线程修改了此数据就好了。 如何实现乐观锁? 实现乐观锁的关键是要保证数据提交时的原子性,通常有两种方式来实现: 基于版本号的乐观锁:通过给数据增加一个版本号,每次操作都需要比较版本号是否一致,只有版本号一致…

    Java 2023年5月18日
    00
  • 微信小程序组件化开发的实战步骤

    下面我会详细讲解“微信小程序组件化开发的实战步骤”的完整攻略,共分为以下几个步骤: 1. 创建自定义组件 首先,在小程序项目中新建一个文件夹,用来存放自定义组件。命名可以根据需要自行定义,这里以 components 为例。在文件夹中按照组件的需求创建各个组件文件夹,比如 toast(提示框组件)、modal(弹框组件)等。 在组件文件夹中,需要新建三个文件…

    Java 2023年5月23日
    00
  • jsp中为表格添加水平滚动条的方法

    当表格内容过长时,我们可能会希望在表格中添加水平滚动条以便于查看。下面是一种使用CSS和Javascript在JSP中添加水平滚动条的方法: 在JSP页面中,定义一个带有id属性的div元素作为表格容器,并设置一个合适的高度和宽度: <div id="table-container" style="height: 300p…

    Java 2023年6月15日
    00
  • SSM项目频繁打成war包部署,使用tomcat和maven实现热部署配置

    下面是SSM项目频繁打成war包部署并使用tomcat和maven实现热部署配置的完整攻略。 1. 前置条件 在开始之前,确保以下条件已满足: 项目使用maven进行构建 tomcat服务器已正确安装并运行 项目使用spring、spring mvc、mybatis等框架 2. 配置pom.xml文件 在项目的pom.xml文件中添加以下依赖: <de…

    Java 2023年5月19日
    00
  • 解决Springboot启动报错:类文件具有错误的版本61.0,应为 52.0

    针对SpringBoot启动报错“类文件具有错误的版本61.0,应为52.0”,按照以下步骤进行解决: 1.问题原因 这个问题通常是因为编译器和运行环境版本不一致。使用较高版本的编译器编译的类文件,在低版本的运行环境中无法运行,导致启动失败。 2.解决过程 2.1 确认编译器和运行环境版本 首先需要确认代码使用的编译器版本以及部署环境的JDK版本是否一致。可…

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