通过Google在React+Spring应用程序中集成OAuth2.0

slmsl1lt  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(30)

我正在使用React和Spring开发一个Web应用程序,我需要帮助使用Google通过OAuth2.0设置授权。在我的React代码中,我使用@react-oauth/google library,成功授权后,我从Google获取用户凭据。
现在我使用的是通过电子邮件+密码授权,但现在我想添加通过OAuth2授权的功能。
问题:
1.在前端从Google获取数据后,我应该怎么做?
1.我需要在Spring应用程序中更改什么以及如何更改才能允许通过OAuth2.0进行授权?
在React中的代码中从Google检索数据:

import { GoogleLogin } from '@react-oauth/google';
import { jwtDecode } from 'jwt-decode';
import React from 'react';
const OAuthButtons = () => {
  const handleSuccess = (credentialResponse) => {
    const decodedToken = jwtDecode(credentialResponse.credential);
  };

  return (
    <div>
      <GoogleLogin
        onSuccess={handleSuccess}
        onError={() => {
          console.log('Login Failed');
        }}
        useOneTap
      />
    </div>
  );
};

export default OAuthButtons;

字符串
Spring中我的restController用于用户授权:

@RestController
@RequestMapping("/api/v1/auth")
public class AuthenticationRestController {

    private final UserFacade userFacade;

    private final AuthenticationManager authenticationManager;

    private final JwtTokenProvider jwtTokenProvider;

    public AuthenticationRestController(UserFacade userFacade, AuthenticationManager authenticationManager, JwtTokenProvider jwtTokenProvider) {
        this.userFacade = userFacade;
        this.authenticationManager = authenticationManager;
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @PostMapping("/registration")
    public ResponseEntity<?> registration(@RequestBody UserRequestDto userRequestDto) {
        try {
            UserResponseDto user = userFacade.createUser(userRequestDto);

            if (user != null) {
                authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getId(), userRequestDto.getPassword()));
                String token = jwtTokenProvider.createToken(user.getId(), user.getRole());
                return ResponseEntity.ok(new UserWithJwtResponseDto(token, user));
            } else {
                throw new EntityExistException("");
            }
        } catch (EntityExistException e) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(e.getMessage());
        }
    }

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody UserRequestDto req) {
        try {
            UserResponseDto user = userFacade.findUserByEmail(req.getEmail());
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getId(), req.getPassword()));

            String token = jwtTokenProvider.createToken(user.getId(), user.getRole());

            return ResponseEntity.ok(new UserWithJwtResponseDto(token, user));
        } catch (AuthenticationException e) {
            throw new BadCredentialsException("Invalid username or password");
        }
    }
}


我在服务器上的SecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtTokenProvider jwtTokenProvider;

    private static final String ADMIN_ENDPOINT = "/api/v1/admin/**";
    private static final String LOGIN_ENDPOINT = "/api/v1/auth/**";
    private static final String USER_ENDPOINT = "/api/v1/user/**";
    private static final String TEACHER_REGISTRATION_ENDPOINT = "/api/v1/teacher/registrationTeacher";
    private static final String TEACHER_ENDPOINT = "/api/v1/teacher/**";
    private static final String COURSES_FOR_NOT_AUTH_ENDPOINT = "/api/v1/course/findAll";
    private static final String ERROR = "/error";

    @Autowired
    public SecurityConfig(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .cors().and()
                    .exceptionHandling()
                .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                    .authorizeRequests()
                    .antMatchers(LOGIN_ENDPOINT).permitAll()
                    .antMatchers(ERROR).permitAll()
                    .antMatchers(COURSES_FOR_NOT_AUTH_ENDPOINT).permitAll()
                    .antMatchers(ADMIN_ENDPOINT).hasRole(" developers:write")
                    .antMatchers(USER_ENDPOINT).hasRole("developers:read")
                    .antMatchers(TEACHER_REGISTRATION_ENDPOINT).hasRole("developers:read")
                    .antMatchers(TEACHER_ENDPOINT).hasRole("developers:educate")
                    .anyRequest().authenticated()
                .and()
                    .apply(new JwtConfigurer(jwtTokenProvider))
                .and()
                .httpBasic();;

    }
}


我的UserDetails安装:

@Service
public class JwtUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    public JwtUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findById(username).orElse(null);

        if (user == null) {
            throw new UsernameNotFoundException("User with username: " + username + " not found");
        }

        JwtUser jwtUser = InnerConverter.convertUserToJwtUser(user);
        if (!jwtUser.isEnabled()) {
            throw new DisabledException("User account is disabled");
        }
        return jwtUser;
    }
}

0lvr5msh

0lvr5msh1#

我有个坏消息

  • @react-oauth/google使您的JavaScript前端成为OAuth2“公共”客户端,现在不鼓励这样做。您应该只使用OAuth2“机密”客户端,它们运行在您信任的服务器上
  • Google提供的访问令牌的受众是Google。要知道,您很可能无法轻松/有效地使用这些访问令牌来授权对您自己的资源服务器的请求。您必须设置一个自己的授权服务器,并具有“使用Google登录”功能。

从那里去哪里:

  • 选择并配置授权服务器。大多数OIDC提供的服务包括“使用...登录"。您可以考虑:
  • 像Keycloak这样的独立解决方案
  • Auth 0、Okta、Amazon Cognito等云服务
  • 使用spring_authorization_server框架“自己动手”(可能不是一个好主意,除非您对OAuth2和OpenID标准有深入的了解)
  • 选择一个BackendFFrontend,您可以使用authorization_code流配置它,并在会话(对来自SPA的请求进行授权)和访问令牌(对资源服务器的请求进行授权)之间进行桥接。spring-cloud-gateway可以轻松地使用oauth2Login()(使用spring-boot-starter-oauth2-client)和TokenRelay筛选器进行配置。
  • 在你的React应用中,将令牌安全替换为会话+ CSRF安全。

我写了a tutorial for using spring-cloud-gateway as BFF。它是为Angular写的,但将其移植到React是微不足道的。

相关问题