SpringBoot整合SpringSecurity实现JWT认证的项目实践

yizhihongxing

下面就给您详细讲解“SpringBoot整合SpringSecurity实现JWT认证的项目实践”的完整攻略。

一、什么是JWT

JWT(JSON Web Token)是一种用于对信息进行安全传输的开放标准,它将信息进行编码后生成一段字符串,用于在不同业务系统之间传递信息。在进行身份验证时,JWT通常被用于对用户进行身份认证和授权,它被广泛地应用于多语言和多平台上简化身份验证和授权流程。

二、为什么要使用JWT

相较于传统的Session和Cookie认证方式,使用JWT认证具有以下优势:

  1. 简化开发过程,开发人员只需要实现JWT生成和校验逻辑即可,避免了很多繁琐的Session和Cookie管理任务。

  2. 分布式应用友好,在多个服务器之间共享认证状态变得更加容易。

  3. 安全性高,JWT使用基于密钥的认证方式,可以防止中间人攻击和数据篡改。

三、SpringBoot整合SpringSecurity实现JWT认证的流程

  1. 引入相关依赖

在使用SpringBoot整合SpringSecurity实现JWT认证之前,我们需要在项目中引入一些相关依赖,包括:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
  1. 实现用户认证逻辑

在进行JWT认证之前,我们需要先实现用户认证逻辑。可以通过继承SpringSecurity提供的UserDetailsService接口,实现自定义的用户认证逻辑。

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username + " not found");
        }

        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Role role : user.getRoles()) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        return new org.springframework.security.core.userdetails.User(user.getUsername(),
                user.getPassword(), authorities);
    }
}
  1. 实现JWT生成和校验逻辑

使用JWT进行身份认证和授权,需要实现JWT的生成和校验逻辑。这里我们可以使用jjwt库进行实现。

@Service
public class JwtTokenProvider {
    private static final Logger logger = LoggerFactory.getLogger(JwtTokenProvider.class);

    private static String jwtSecret = "jwtSecret";

    private static int jwtExpirationInMs = 604800000;

    public static String generateToken(Authentication authentication) {
        User principal = (User) authentication.getPrincipal();

        Date expirationDate = new Date(System.currentTimeMillis() + jwtExpirationInMs);

        return Jwts.builder()
                .setSubject(principal.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public static boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException ex) {
            logger.error("Invalid JWT signature");
        } catch (MalformedJwtException ex) {
            logger.error("Invalid JWT token");
        } catch (ExpiredJwtException ex) {
            logger.error("Expired JWT token");
        } catch (UnsupportedJwtException ex) {
            logger.error("Unsupported JWT token");
        } catch (IllegalArgumentException ex) {
            logger.error("JWT claims string is empty.");
        }
        return false;
    }

    public static String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody();

        return claims.getSubject();
    }
}
  1. 配置JWT认证过滤器

在SpringSecurity中,我们可以通过实现一个过滤器来进行JWT认证,代码如下:

public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = getJwtFromRequest(request);

            if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) {
                String username = jwtTokenProvider.getUsernameFromToken(jwt);

                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception ex) {
            logger.error("Could not set user authentication in security context", ex);
        }

        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}
  1. 配置WebSecurity配置类

在配置SpringSecurity时,我们需要配置一个WebSecurity配置类,代码如下:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                    .and()
                .csrf()
                    .disable()
                .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler)
                    .and()
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                .authorizeRequests()
                    .antMatchers("/api/auth/**")
                        .permitAll()
                    .anyRequest()
                        .authenticated();

        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

四、示例1:用户登录

在前端页面中,用户输入用户名和密码,将信息发送到后台,进行认证,并通过JWT生成和返回认证所需的Token信息,下面是示例代码:

function login(username, password) {
    return axios.post('/api/auth/login', {
        username: username,
        password: password
    }).then(response => {
        if (response.data.token) {
            localStorage.setItem('user', JSON.stringify(response.data));
        }
        return response.data;
    });
}

在后端中,我们实现了/login接口,用于接收前端发送的用户名和密码信息,并进行JWT认证和Token的生成,代码如下:

@RestController
@RequestMapping("/api/auth")
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private UserRepository userRepository;

    @PostMapping("/login")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(),
                        loginRequest.getPassword()
                )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);

        String jwt = jwtTokenProvider.generateToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
    }
}

五、示例2:使用Token进行用户认证

在前端发起请求时,在Http请求头中添加Authorization字段,值为“Bearer ”和Token内容构成的字符串,用于在后台进行认证。示例代码如下:

function getUserInfo() {
    const user = JSON.parse(localStorage.getItem('user'));

    if (user && user.token) {
        return axios.get('/api/user/me', {
            headers: { 'Authorization': 'Bearer ' + user.token }
        }).then(response => {
            return response.data;
        });
    }

    return null;
}

在后端中,我们实现了一个/me接口,用于获取当前用户的信息,请参考示例代码:

@RestController
@RequestMapping("/api/user")
public class UserController {
    @Autowired
    private UserRepository userRepository;

    @GetMapping("/me")
    @PreAuthorize("hasRole('USER')")
    public UserSummary getCurrentUser(@CurrentUser UserPrincipal currentUser) {
        UserSummary userSummary = new UserSummary(currentUser.getId(), currentUser.getUsername(), currentUser.getEmail());
        return userSummary;
    }
}

六、总结

到这里,我们已经讲解了“SpringBoot整合SpringSecurity实现JWT认证的项目实践”的完整流程,并提供了两个示例用于帮助读者理解如何在实际项目中应用JWT认证。相信读者已经掌握了相关的技能,可以在自己的项目中应用JWT认证。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot整合SpringSecurity实现JWT认证的项目实践 - Python技术站

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

相关文章

  • Maven 错误找不到符号的解决方法

    下面是详细的Maven错误找不到符号的解决方法攻略。 1. 问题描述 在使用Maven构建Java项目时,有时代码能够正常通过编译,但是在执行mvn clean package时可能会出现以下错误信息: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:…

    Java 2023年5月19日
    00
  • Java深入浅出数组的定义与使用上篇

    我来为你讲解一下“Java深入浅出数组的定义与使用上篇”的完整攻略。 标题 标题应该使用Markdown语法中的“#”,一级标题用“#”表示,二级标题用“##”表示,以此类推。这篇攻略的一级标题可以命名为“Java深入浅出数组的定义与使用上篇”。 正文 在开始正文之前,需要简单介绍一下本文主要讲解的内容。本篇攻略主要分为三个部分,分别是数组的定义、数组的初始…

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

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

    Java 2023年5月19日
    00
  • Java启动Tomcat的实现步骤

    Java启动Tomcat的实现步骤如下: 1. 确认Tomcat安装目录 首先需要确认Tomcat安装目录,以便后续操作。假设Tomcat的安装目录为 /usr/local/tomcat8。 2. 设置JAVA_HOME环境变量 在启动Tomcat之前,需要设置JAVA_HOME环境变量,确保Java环境可用。在Linux系统中,可以通过以下命令设置: ex…

    Java 2023年5月19日
    00
  • JSP技术简介

    JSP技术是运用Java语言的Web编程技术之一,以便于开发人员动态地生成HTML、XML或其他类型的Web页面。在JSP页面中,可以将静态内容、JSP标记和Java代码混合在一起来生成动态Web页面。 JSP页面结构 JSP页面以.jsp后缀作为文件后缀名。在JSP页面中,可以包含以下几种元素: 指令:指示服务器或容器如何翻译JSP页面,并且在整个页面中只…

    Java 2023年6月15日
    00
  • springboot整合mybatis的超详细过程(配置模式+注解模式)

    Spring Boot整合MyBatis的超详细过程 MyBatis是一种优秀的持久层框架,可以帮助我们更好地管理数据库。在Spring Boot应用程序中,我们可以使用MyBatis来访问数据库。本文将详细讲解如何在Spring Boot应用程序中整合MyBatis,包括配置模式和注解模式。 步骤一:添加依赖 我们需要在pom.xml文件中添加以下依赖项:…

    Java 2023年5月15日
    00
  • 深入理解java long 存储时间戳

    深入理解Java long存储时间戳攻略 前言 在Java开发中,时间戳是一个很常见的概念,它可以表示一个时间点距离某个固定的参考时间点(称为基准时间)的时间差。时间戳通常用来表示事件发生的时间,或者是开发者自己记录的某个状态改变的时间,因为时间戳是一个标准的数字表示方式,因此使用广泛。 在Java中,通常使用long类型来存储时间戳。然而,Java lon…

    Java 2023年5月20日
    00
  • 多端登录如何实现踢人下线需求实现

    实现多端登录下的踢人下线需求,可以采用以下几种方法: 基于Token和Session实现 方案简介:采用Token和Session配合,来实现多端登录下的踢人下线需求实现。 接口可以采用Token认证,每次客户端请求接口时,服务端进行Token验证并通过Session记录Token。 当用户进行登录操作时,客户端请求登录接口,服务端通过验证用户的账号和密码,…

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