我遇到了一个奇怪的情况。
我知道的是:
为了让它登录,我需要将凭证作为x-www-form-urlencoded
POST请求发送。用户提供正确的凭据,它传递并向用户提供访问令牌和刷新令牌,如果没有,则会失败,并且不会提供任何这些令牌--这正是人们所期望的。
现在,一旦登录并尝试访问一个资源--在本例中是我拥有的用户列表--它会失败,出现403个禁止的错误。我目前正在使用PostMan来测试API。登录后我提出的初始POST
请求是带有Bearer Token
授权的,在其中我使用访问令牌。但失败了。在Spring上调试代码之后:
@Slf4j
public class AuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
if(request.getServletPath().equals("api/login") || request.getServletPath().equals("/api/token/refresh")) {
filterChain.doFilter(request, response);
} else {
String authorizationHeader = request.getHeader(AUTHORIZATION);
if(authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
// TODO: Refactor this to a utility class.
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = verifier.verify(token);
String username = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
stream(roles).forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role));
});
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
} catch (Exception exception) {
log.error("Error logging in: " + exception.getMessage());
Map<String, String> error = new HashMap<>();
error.put("error_message", exception.getMessage());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
} else {
filterChain.doFilter(request, response);
}
}
}
}
我发现token
返回null。好的..。让我们尝试以x-www-form-urlencoded
的形式发送它。token
捡起寄送的令牌..。太棒了!在filterChain.doFilter(request, response);
之后,一路踩进代码,在Spring代码中到达requiresAuthentication()
.这是返回false
,这是好的..。这看起来真不错。
然而,返回邮递员- Status: 403 Forbidden
.哦-怎么做?查看Spring的日志,我选择了以下与我的url入口点相关的日志:
2022-04-16 08:36:47.267 DEBUG 21000 --- [nio-8102-exec-4] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(1683533175<open>)] after transaction
2022-04-16 08:36:47.275 DEBUG 21000 --- [nio-8102-exec-4] o.s.s.a.dao.DaoAuthenticationProvider : Failed to authenticate since no credentials provided
2022-04-16 08:36:47.275 DEBUG 21000 --- [nio-8102-exec-4] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2022-04-16 08:36:47.275 DEBUG 21000 --- [nio-8102-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2022-04-16 08:36:47.275 DEBUG 21000 --- [nio-8102-exec-4] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2022-04-16 08:36:47.285 DEBUG 21000 --- [nio-8102-exec-4] o.s.security.web.FilterChainProxy : Securing GET /error
作为新手,我不知道该如何着手解决这个问题。
编辑:
这是我当前的安全配置:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Lazy
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/login/**", "/api/login/**", "/api/token/refresh/**").permitAll();
http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/users/**").hasAnyAuthority("ROLE_USER");
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/user/save/**").hasAnyAuthority("ROLE_ADMIN");
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/role/assign-to-user/**").hasAnyAuthority("ROLE_ADMIN");
http.authorizeRequests().anyRequest().authenticated();
http.addFilter(new AuthenticationFilter(authenticationManagerBean()));
http.addFilterBefore(new AuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
protected CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(List.of("*"));
config.setAllowedMethods(List.of("*"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
config.applyPermitDefaultValues();
source.registerCorsConfiguration("/**", config);
return source;
}
}
AuthenticationFilter:
@Slf4j
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
public AuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(
HttpServletRequest request,
HttpServletResponse response
) throws AuthenticationException {
String username = request.getParameter("username");
String password = request.getParameter("password");
log.info("Username: \"" + username + "\", password: \"" + password + "\"");
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
return authenticationManager.authenticate(authenticationToken);
}
@Override
protected void successfulAuthentication(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authentication
) throws IOException, ServletException {
User user = (User) authentication.getPrincipal();
// TODO: Generate secret key that is a little more secure than this.
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
String accessToken = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 10 * 60 * 1000))
.withIssuer(request.getRequestURL().toString())
.withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);
String refreshToken = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
.withIssuer(request.getRequestURL().toString())
.sign(algorithm);
Map<String, String> tokens = new HashMap<>();
tokens.put("access_token", accessToken);
tokens.put("refresh_token", refreshToken);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), tokens);
}
}
发布于 2022-04-16 22:13:17
我注意到AuthorizationFilter创建了权限,但没有在UsernamePasswordAuthenticationToken中设置它们。你的安保人员需要授权。
https://stackoverflow.com/questions/71892024
复制相似问题