实现身份验证和授权
接下来,我们需要实现基于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的过滤器链中。它应该在用户名密码身份验证过滤器之前运行。