Spring Boot 中使用 Flutter 前端进行 Json 身份验证

问题描述 投票:0回答:1

我试图通过 JSON 发送用户名和密码,在 spring boot 中使用 flutter 前端制作一个登录页面。 IP 将请求从我的 Android 模拟器发送到本地主机。

按下提交按钮时,将运行以下颤振代码:

Future<String> sendLogin(
    String username, String password, BuildContext context) async {
  var url = "http://10.0.2.2:8080/login";
  var response = await http.post(Uri.parse(url),
      headers: <String, String>{"Content-Type": "application/json"},
      body: jsonEncode(<String, String>{
        "username": username,
        "password": password,
      }));
  url = "http://10.0.2.2:8080/protected-resource";
  response = await http.get(Uri.parse(url));
  return response.body;

}

我的 Spring Boot 后端看起来像这样

-安全配置:

@Configuration
@EnableGlobalMethodSecurity(
        prePostEnabled = true,
        securedEnabled = true,
        jsr250Enabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAuthenticationProvider authProvider;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CustomFilter mupaf = new CustomFilter();
        mupaf.setAuthenticationManager(authenticationManager());

        http
                .csrf().disable()
                .addFilterAt(
                    mupaf,
                  UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/h2/**")
                .permitAll()
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/protected-resource").authenticated()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
        http.authenticationProvider(authProvider);
    }

}

自定义过滤器:

public class CustomFilter extends AbstractAuthenticationProcessingFilter {

protected CustomFilter() {
    super(new AntPathRequestMatcher("/login", "POST"));
}

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

    String username, password;

    try {
        Map<String, String> requestMap = new ObjectMapper().readValue(request.getInputStream(), Map.class);
        username = requestMap.get("username");
        password = requestMap.get("password");
        System.out.println(username+ " "+password+" Tried to log in");
    } catch (IOException e) {
        throw new AuthenticationServiceException(e.getMessage(), e);
    }

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
            username, password);

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

}

身份验证提供商:

 @Component
@RequiredArgsConstructor
public class MyAuthenticationProvider implements AuthenticationProvider {


    private final UserRepository userRepository;

    @Override
    public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
        final UsernamePasswordAuthenticationToken upAuth = (UsernamePasswordAuthenticationToken) authentication;
        final String name = (String) authentication.getPrincipal();

        final String password = (String) upAuth.getCredentials();

        final String storedPassword = userRepository.findByUsername(name).map(User::getPassword)
                .orElseThrow(() -> new BadCredentialsException("illegal id or passowrd"));

        if (Objects.equals(password, "") || !Objects.equals(password, storedPassword)) {
            throw new BadCredentialsException("illegal id or passowrd");
        }

        final Object principal = authentication.getPrincipal();
        final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
                principal, authentication.getCredentials(),
                Collections.emptyList());
        result.setDetails(authentication.getDetails());

        return result;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

当我通过邮递员发送用户名和密码时,我可以登录并访问受保护的资源。但是当我通过flutter前端做同样的事情时,登录成功但是无法访问受保护的资源(错误403)。

我在这里缺少什么导致了这个问题?

spring spring-boot flutter spring-security
1个回答
0
投票

发生的情况是,登录后,Spring Boot 使用会话(通常通过 Cookie)来跟踪经过身份验证的状态。当您通过邮递员登录时,它会为您处理会话。但在 flutter 中,您需要自己管理。 因此,您应该使用 http.Client 来保持会话处于活动状态,而不是发出两个单独的请求。具体方法如下: 飞镖

import 'package:http/http.dart' as http;

    Future<String> sendLogin(
        String username, String password, BuildContext context) async {
      var client = http.Client();
      var url = "http://10.0.2.2:8080/login";
      
      var response = await client.post(
        Uri.parse(url),
        headers: <String, String>{"Content-Type": "application/json"},
        body: jsonEncode(<String, String>{
          "username": username,
          "password": password,
        }),
      );
    
      if (response.statusCode == 200) {
        // login was successful, now access protected resource
        url = "http://10.0.2.2:8080/protected-resource";
        response = await client.get(Uri.parse(url));
    
        return response.body;
      } else {
        throw Exception('Failed to log in');
      }
    }

使用 http.Client,会话会转移到第二个请求,因此当您点击 /protected-resource 时,Spring Boot 会识别该会话并允许您访问它。这应该可以解决您遇到的 403 问题。

© www.soinside.com 2019 - 2024. All rights reserved.