source

스프링 부트 + Oauth2 클라이언트 자격 정보

manycodes 2023. 2. 25. 21:25
반응형

스프링 부트 + Oauth2 클라이언트 자격 정보

Spring Boot 시 클라이언트 credentials 흐름과 함께 Ath2를 사용하여 마이크로 서비스를 보호하려고 합니다.

덧붙여서, 이러한 마이크로 서비스는 미들웨어 레이어에서만 서로 대화합니다.즉, 인증(Facebook으로서의 사용자 로그인 프로세스)을 허용하기 위해 사용자 자격 정보가 필요하지 않습니다.

이 통신을 관리하기 위한 인증 및 자원 서버를 작성하는 방법을 나타내는 샘플을 인터넷에서 찾았습니다.다만, 유저 credential(3개의 다리)을 사용해 조작하는 방법을 설명하는 예를 발견했습니다.

Spring Boot 및 Oauth2에서의 방법 샘플이 있습니까?사용하는 스코프에 대해 좀 더 자세히 알려주시면 토큰 교환을 해주시면 감사하겠습니다.

REST 서비스는 Oauth2 Client credentials 스킴으로 보호되고 있습니다.리소스와 권한 부여 서비스가 동일한 앱에서 실행 중이지만 다른 앱으로 분할할 수 있습니다.

@Configuration
public class SecurityConfig {

@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {

    // Identifies this resource server. Usefull if the AuthorisationServer authorises multiple Resource servers
    private static final String RESOURCE_ID = "*****";

    @Resource(name = "OAuth")
    @Autowired
    DataSource dataSource;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http    
                .authorizeRequests().anyRequest().authenticated();
        // @formatter:on
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(RESOURCE_ID);
        resources.tokenStore(tokenStore());
    }

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }
}

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Resource(name = "OAuth")
    @Autowired
    DataSource dataSource;

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore());
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }
}
}

Oauth2 테이블의 데이터 소스 설정:

@Bean(name = "OAuth")
@ConfigurationProperties(prefix="datasource.oauth")
public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
}

인증 및 자원 서버와의 통신 방법은 다음과 같습니다.

curl -H "Accept: application/json" user:password@localhost:8080/oauth/token -d grant_type=client_credentials
curl -H "Authorization: Bearer token" localhost:8080/...

Oauth2 데이터베이스에는 다음 레코드가 있습니다.

client_id  resource_ids  client_secret  scope  authorized_grant_types   web_server_redirect_uri  authorities  access_token_validity refresh_token_validity  additional_information  autoapprove
user  ****  password  NULL  client_credentials  NULL  X  NULL  NULL  NULL  NULL

클라이언트 어플리케이션의 resttemplate

@Configuration
@EnableOAuth2Client
public class OAuthConfig {

@Value("${OAuth2ClientId}")
private String oAuth2ClientId;

@Value("${OAuth2ClientSecret}")
private String oAuth2ClientSecret;

@Value("${Oauth2AccesTokenUri}")
private String accessTokenUri;

@Bean
public RestTemplate oAuthRestTemplate() {
    ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
    resourceDetails.setId("1");
    resourceDetails.setClientId(oAuth2ClientId);
    resourceDetails.setClientSecret(oAuth2ClientSecret);
    resourceDetails.setAccessTokenUri(accessTokenUri);

    /*

    When using @EnableOAuth2Client spring creates a OAuth2ClientContext for us:

    "The OAuth2ClientContext is placed (for you) in session scope to keep the state for different users separate.
    Without that you would have to manage the equivalent data structure yourself on the server,
    mapping incoming requests to users, and associating each user with a separate instance of the OAuth2ClientContext."
    (http://projects.spring.io/spring-security-oauth/docs/oauth2.html#client-configuration)

    Internally the SessionScope works with a threadlocal to store variables, hence a new thread cannot access those.
    Therefore we can not use @Async

    Solution: create a new OAuth2ClientContext that has no scope.
    *Note: this is only safe when using client_credentials as OAuth grant type!

     */

//        OAuth2RestTemplate restTemplate = new      OAuth2RestTemplate(resourceDetails, oauth2ClientContext);
    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, new DefaultOAuth2ClientContext());

    return restTemplate;
}
}

restTemplate를 삽입하여 Oauth2 시큐어 서비스에 (비동기적으로) 대화할 수 있습니다.현재는 스코프를 사용하지 않습니다.

Spring-boot-2.7 및 Java 17로 업데이트합니다.

https://chuangtc.com/Java/spring-boot-27-security-social-login.php

public class SecurityConfig {

@Value("${spring.social.facebook.appSecret}")
String appSecret;

@Value("${spring.social.facebook.appId}")
String appId;

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private FacebookConnectionSignup facebookConnectionSignup;

@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
    return http.getSharedObject(AuthenticationManagerBuilder.class)
        .userDetailsService(userDetailsService)
        .and()
        .build();
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf()
        .disable()
        .authorizeRequests()
        .antMatchers("/login*", "/signin/**", "/signup/**")
        .permitAll()
        .anyRequest()
        .authenticated()
        .and()
        .formLogin()
        .loginPage("/login")
        .permitAll()
        .and()
        .logout();
    return http.build();
}

@Bean
// @Primary
public ProviderSignInController providerSignInController() {
    ConnectionFactoryLocator connectionFactoryLocator = connectionFactoryLocator();
    UsersConnectionRepository usersConnectionRepository = getUsersConnectionRepository(connectionFactoryLocator);
    ((InMemoryUsersConnectionRepository) usersConnectionRepository).setConnectionSignUp(facebookConnectionSignup);
    return new ProviderSignInController(connectionFactoryLocator, usersConnectionRepository, new FacebookSignInAdapter());
}

private ConnectionFactoryLocator connectionFactoryLocator() {
    ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
    registry.addConnectionFactory(new FacebookConnectionFactory(appId, appSecret));
    return registry;
}

private UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
    return new InMemoryUsersConnectionRepository(connectionFactoryLocator);
}

}

Facebook SignIn 어댑터

@Service
public class FacebookSignInAdapter implements SignInAdapter {
@Override
public String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) {
    System.out.println(" ====== Sign In adapter");
    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(connection.getDisplayName(), null, Arrays.asList(new SimpleGrantedAuthority("FACEBOOK_USER"))));
    return null;
}
}

언급URL : https://stackoverflow.com/questions/37534073/spring-boot-oauth2-client-credentials

반응형