简体   繁体   English

使用解析 JSON 有效负载的自定义身份验证过滤器在身份验证后禁止获取 403

[英]Getting 403 forbidden after authentication using custom authentication filter that parses JSON payload

What I'm trying to do is just authenticate in-memory default user using a custom authentication filter that parses a JSON payload that contain the username and the password.我想要做的只是使用自定义身份验证过滤器对内存中的默认用户进行身份验证,该过滤器解析包含用户名和密码的 JSON 有效负载。

SecurityConfig.java安全配置.java

package ali.yousef.authdemo.config.security;

@Configuration
@EnableWebSecurity
public class SecurityConfig
{
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception
    {
        AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();

        return authenticationManager;
    }

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

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception
    {
        JsonUserPasswordAuthenticationFilter jsonUserPasswordAuthenticationFilter = new JsonUserPasswordAuthenticationFilter();
        jsonUserPasswordAuthenticationFilter.setAuthenticationManager(authenticationManager);

        http
                .csrf().disable()
                .formLogin().disable()
                .addFilterAt(jsonUserPasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeHttpRequests()
                .requestMatchers("/api/**").authenticated()
                .anyRequest().permitAll();

        return http.build();
    }
}

JsonUserPasswordAuthenticationFilter.java JsonUserPasswordAuthenticationFilter.java

package ali.yousef.authdemo.config.security;

public class JsonUserPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter
{
    protected JsonUserPasswordAuthenticationFilter(AuthenticationManager authenticationManager)
    {
        this.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException
    {
        UsernamePasswordDto usernamePasswordDto;

        try
        {
            usernamePasswordDto = new ObjectMapper().readValue(request.getInputStream(), UsernamePasswordDto.class);
            System.out.println(usernamePasswordDto.toString());
        }
        catch (IOException ioe)
        {
            throw new AuthenticationServiceException(ioe.getMessage(), ioe);
        }

        UsernamePasswordAuthenticationToken authToken =
                new UsernamePasswordAuthenticationToken(usernamePasswordDto.getUsername(), usernamePasswordDto.getPassword());

        return this.getAuthenticationManager().authenticate(authToken);
    }
}

TestController.java测试控制器.java

@RestController
public class TestController
{
    @GetMapping("/api/hello")
    public String hello(Principal principal)
    {
        return "hello " + principal.getName();
    }
}

When authenticating the default user it gets authenticated and return the home page but when I try to send a request to /api/hello it respond with 403 .在对默认用户进行身份验证时,它会通过身份验证并返回主页,但是当我尝试向/api/hello发送请求时,它会以403响应。

EDIT: I edited how I register the custom authentication filter.编辑:我编辑了我如何注册自定义身份验证过滤器。 But the same problem is present.但是存在同样的问题。 It seems like the security context gets cleared after successful authentication and I get anonymousUser from principal.似乎安全上下文在身份验证成功后被清除,我从主体那里得到了anonymousUser用户。

Extending a UsernamePassWordAuthenticationFilter brings in more customizations than you need to set up a custom auth filter.. see this post for more details why your filter is not getting called - link扩展 UsernamePassWordAuthenticationFilter 带来的定制比设置自定义身份验证过滤器所需的更多。请参阅此帖子了解更多详细信息,了解为什么您的过滤器未被调用 - 链接

You can achieve the same using OncePerRequestFilter as below -您可以使用 OncePerRequestFilter 实现相同的效果,如下所示 -

@Component
public class JsonUserPasswordAuthenticationFilter extends OncePerRequestFilter
{

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    
        UsernamePasswordAuthenticationToken authToken = YOUR_LOGIC(); // new UsernamePasswordAuthenticationToken("test", "passwd",Collections.emptyList()); as you have no authorities empty list is important here...
    
        SecurityContextHolder.getContext().setAuthentication(authToken);

        filterChain.doFilter(request, response);
    
    }
}

@Configuration
@EnableWebSecurity
public class SecurityConfig
{

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

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, JsonUserPasswordAuthenticationFilter filter) throws Exception {
    http
        .csrf().disable()
        .formLogin().disable()
        .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
        .authorizeHttpRequests(auth -> {
          auth.requestMatchers(new AntPathRequestMatcher("/api/**")).authenticated()
        .anyRequest().permitAll();
        })  ;

    return http.build();
}    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM