使用Spring Security和JWT来进行身份验证和授权(三)

2023-04-14 07:25:18 浏览数 (3)

实现身份验证和授权

接下来,我们需要实现基于JWT的身份验证和授权。可以使用以下代码实现:

代码语言:javascript复制
@Service
public class JwtUserDetailsService 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("User not found with username: "   username);
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
                new ArrayList<>());
    }

}

上述代码中,我们定义了一个名为“JwtUserDetailsService”的类,它实现了UserDetailsService接口。该类从数据库中获取用户信息,并将其转换为Spring Security用户详细信息对象。

接下来,我们需要实现JWT身份验证入口点。可以使用以下代码实现:

代码语言:javascript复制
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }

}

上述代码中,我们定义了一个名为“JwtAuthenticationEntryPoint”的类,它实现了AuthenticationEntryPoint接口。该类用于在未经身份验证的情况下拒绝请求,并返回HTTP状态代码401。

最后,我们需要实现JWT请求过滤器。可以使用以下代码实现:

代码语言:javascript复制
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;
        String jwtToken = null;
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                logger.error("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                logger.error("JWT Token has expired");
            }
        } else {
            logger.warn("JWT Token does not begin with Bearer String");
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);

            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }

}

上述代码中,我们定义了一个名为“JwtRequestFilter”的类,它扩展了Spring Security的OncePerRequestFilter类。该类用于过滤所有请求,并验证JWT令牌。如果JWT令牌有效,则设置Spring Security上下文的身份验证信息。

现在我们需要将这些组件集成到我们的Spring Boot应用程序中。可以使用以下代码实现:

代码语言:javascript复制
@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }

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

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

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll().anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

上述代码中,我们定义了一个名为“SecurityConfigurer”的类,它扩展了Spring Security的WebSecurityConfigurerAdapter类。该类用于配置身份验证和授权规则,以及安全过滤器链。我们在这里配置了以下内容:

  • 我们允许访问“/authenticate”端点而不需要身份验证。这是我们用于生成JWT令牌的端点。
  • 我们要求对所有其他请求进行身份验证。
  • 我们配置了JWT身份验证入口点(jwtAuthenticationEntryPoint)和JWT请求过滤器(jwtRequestFilter)。
  • 我们配置了会话管理策略为“STATELESS”,这意味着我们将不使用HTTP会话进行身份验证和授权。
  • 我们将JWT请求过滤器添加到Spring Security的过滤器链中。它应该在用户名密码身份验证过滤器之前运行。

0 人点赞