Colab 으로 띄우는게 너무 시간도 오래 걸리고 이것저것 만져보고싶은 생각에 Windows PC 에 설치를 하려 했으나 실패했다.

설치는 매우 간단하지만, 설치 후 SD(Stable Diffusion) 실행 시 VRAM 에 Model 을 올리는것 같은데 VRAM 이 1GB 인 내 노트북이 역시나 실행 최소환경 요건에 맞지 않았다.ㅠㅠ

OutOfMemoryError.. 이럴수가.. OTL

어쩔 수 없이 Colab 으로 가야하는가보다

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

 Spring Security 에 OAuth 2 모듈이 있는걸 알고 있지만 OAuth 로 SSO 서버를 구현해보지는 않았기에 chatGPT 에게 물어봤다


Q > Springboot 의 OAuth 를 활용해 SSO 구현 가능하니?

A > ChatGPT 는 당근 가능하다고 하며 TMI 로 아래처럼 얘기를 붙여준다

 

OAuth 정의 

OAuth는 사용자 자격 증명을 공개하지 않고 보호된 서버에서 사용자 자원에 대한 제3자 응용 프로그램의 액세스를 허용하는 인증 프레임 워크입니다. 최신 웹 애플리케이션 및 API에서 인증 및 권한 부여에 자주 사용됩니다.

Spring Boot는 웹 애플리케이션 및 API를 구축하기위한 인기있는 Java 기반 프레임 워크로서 OAuth를 지원하기 위한 다양한 도구 및 라이브러리를 제공합니다.

Spring Boot를 사용하여 OAuth를 이용한 SSO를 구현하려면 Spring Security 프레임 워크를 사용할 수 있습니다. Spring Security는 OAuth 인증 및 권한 부여를 지원하는 내장 기능을 제공합니다. Spring Security를 구성하여 Google이나 Facebook과 같은 OAuth 공급자를 신원 공급자로 사용하도록 설정할 수 있습니다.

다음은 Spring Boot를 사용하여 OAuth를 이용한 SSO를 구현하는 일반적인 단계입니다.

  1. 새로운 Spring Boot 애플리케이션을 만들거나 기존 애플리케이션을 수정하여 Spring Security를 사용합니다.
  2. Google이나 Facebook과 같은 OAuth 공급자를 선택하고 클라이언트 ID 및 클라이언트 비밀번호를 얻기 위해 공급자에 애플리케이션을 등록합니다.
  3. Spring Security를 구성하여 OAuth 공급자를 신원 공급자로 사용하도록 설정합니다.
  4. OAuth 인증 흐름을 처리하는 필요한 컨트롤러 엔드 포인트 및 사용자 인터페이스를 구현합니다.
  5. 사용자가 인증되면 세션 또는 토큰에 사용자 자격 증명을 저장하여 여러 애플리케이션에서 SSO를 활성화합니다.

Spring Boot를 사용하여 OAuth를 이용한 SSO를 구현하는 방법에 대한 자습서, 가이드 및 샘플 코드를 포함한 많은 온라인 자료가 있습니다. Spring Security 문서는 OAuth 인증 및 권한 부여를 구성하는 방법에 대한 자세한 정보를 제공하는 좋은 출발점입니다.


추가질문

이번에도 나의 질문이 조금 부족했음을 느낀다 나는 SSO Server 를 구현하는 방법을 물어보고 싶었는데, SSO 구현방법을 물어봤다.

다시 수정해서 물어보고 Springboot 기반의 Sample Code 도 달라고 요청했다

 

Q >  역시나 친절하게도 아래처럼 대답해준다 

 

First, you would need to add the necessary dependencies to your pom.xml file:

<dependencies>
    <!-- Spring Security OAuth2 dependencies -->
    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>2.4.0</version>
    </dependency>
    
    <!-- Spring Boot dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.6.2</version>
    </dependency>
</dependencies>

Next, you would need to configure the OAuth2 server in your Spring Boot application. Here is an example configuration class:

@Configuration
@EnableAuthorizationServer
public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {
 
    @Autowired
    private AuthenticationManager authenticationManager;
 
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
            .withClient("client1")
            .secret("secret1")
            .authorizedGrantTypes("authorization_code")
            .scopes("read")
            .redirectUris("http://localhost:8081/login/oauth2/code/client1")
            .and()
            .withClient("client2")
            .secret("secret2")
            .authorizedGrantTypes("authorization_code")
            .scopes("read")
            .redirectUris("http://localhost:8082/login/oauth2/code/client2");
    }
 
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }
 
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("isAuthenticated()");
    }
}

In this example configuration class, we are configuring two clients ("client1" and "client2") with different credentials and redirect URIs. We are also specifying that the clients are authorized to use the "authorization_code" grant type with the "read" scope. Finally, we are specifying that the AuthenticationManager should be used to authenticate clients and users.

You would also need to configure your Spring Boot application to use Spring Security for authentication. Here is an example WebSecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/oauth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .httpBasic()
            .and()
            .csrf().disable();
    }
 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user1")
            .password("{noop}password1")
            .roles("USER")
            .and()
            .withUser("user2")
            .password("{noop}password2")
            .roles("USER");
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
 
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

In this example WebSecurityConfigurerAdapter, we are configuring Spring Security to permit all requests to the "/oauth" endpoint and to require authentication for all other requests. We are also configuring an in-memory UserDetailsService with two users and their passwords,

 

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

오늘 열심히 새로운 프로젝트를 위한 분석설계 작업을 하던 중 옆 동료들과 잠시 머리도 식힐겸 이야기를 하다가 연동 시스템에서 HTTP 요청 시 Spring Boot 기반의 Multi Instance 서버들이 해당 요청을 Broadcast 받은 것 처럼 각 Instance 의 State 들을 업데이트 해야 하는 요건이 생겨 논의하고 있다는걸 알게 되었다.

머리 식히러 왔어서 자리를 피하고 싶었으나.. 최소한의 Effort 로 구현하고 싶고, Message Broker 나 Redis 같은 IMDB, Zookeper 등을 사용하지 않았으면 좋겠다 하고, NoSQL DB 로 MongoDB 를 사용하고 있으나 DB Polling 으로 인해 부하를 주고싶지 않다고 하고..

잠시 생각하던 중 MongoDB 에서 Collection 의 변경이 일어나면 이 이벤트를 Listen 할 수 있는 기능이 생각나서 해당 기능을 사용해서 구현해보는게 어떤가 이야기 했다.

말이 나온김에 ChatGPT 를 통해 Sample Code 를 만들어 보라 시켜봤다.

GPT write a pub sub example springboot java code using mongodb


ChatGPT 놈의 조언

Here is an example of a basic implementation of the publish-subscribe pattern in a Spring Boot application using MongoDB as the message broker:

@Service
public class PublisherService {
    private final MongoTemplate mongoTemplate;

    @Autowired
    public PublisherService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public void publishMessage(String message) {
        mongoTemplate.save(new Message(message));
    }
}

@Document
class Message {
    private String message;

    public Message(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

@Service
public class SubscriberService {
    private final MongoTemplate mongoTemplate;

    @Autowired
    public SubscriberService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @PostConstruct
    public void subscribe() {
        mongoTemplate.getDb().getCollection("message").watch().forEach((Consumer<ChangeStreamDocument<Document>>) changeStreamDocument -> {
            Message message = mongoTemplate.getConverter().read(Message.class, changeStreamDocument.getFullDocument());
            System.out.println("Received message: " + message.getMessage());
        });
    }
}

이녀석 초반에는 무늬만 pub sub 같은 코드를 내놓더니만 몇번 심도있는(?) 대화를 해주고 난 이후에는 Collection 의 watch() 로 ChangeStreamDocument 를 사용해 Event 를 Listen 하는 제대로 되어보이는 코드를 내어준다. 한번 테스트 해보자.

 

테스트 코드

package mongo.account;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Getter
@Setter
@Document(collection = "account")
public class Account {
    @Id
    private String id;
    private String userName;
    private String email;
}
@Repository
public interface AccountRepository extends MongoRepository<Account, String> {
    Account findAccountByUserName(String userName);
    List<Account> findAccountsByUserName(String userName);

    @Query(value = "distinct('userName')", fields = "userName")
    List<String> findDistinct();
}
@Service
@RequiredArgsConstructor
@Slf4j
public class AccountSubscriber {
    private final MongoTemplate mongoTemplate;

    @PostConstruct
    public void subscribe() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                log.info("Registering Subscriber");
                mongoTemplate.getDb().getCollection("account").watch()
                        .forEach((Consumer<ChangeStreamDocument<Document>>) changeStreamDocument -> {
                            Account account = mongoTemplate.getConverter().read(Account.class, changeStreamDocument.getFullDocument());
                            log.info("[{}] userName : {}", changeStreamDocument.getOperationType(), account!=null?account.getUserName():null);
                        });
                log.info("Subscriber Registered");
            }
        });
        t.start();
    }
}
@Bean
    @Order(1)
    public ApplicationRunner applicationRunner() {
        return args -> {
            Account account = new Account();
            account.setUserName("joon");
            account.setEmail("abcdef@naver.com");

            accountRepository.insert(account);
            log.info("Done");

            List<Account> result = accountRepository.findAccountsByUserName("joon");
            log.info("result 1 : {}", result.size());


            // .... 생략 ...

            accountRepository.deleteAll();

        };
    }

 

실행결과

 

오늘도 chatGPT 가 나름 참고할만한 코드를 잘 만들어주었다. 

물론 그대로 갖다 붙여넣는다고 원하는 동작을 하지는 못한다 (뭐 이러면 개발자 죽어야지..). watch() 에서 blocking 되기땜에 thread 로 빼주는 코드를 추가해주는 센스까지는 아직 chatGPT 가 못내주기는 하다마는 그래도 이게 어디냐..

구글링 해서 찾을수도 있지만 chatGPT 를 썼을 때에는 좀더 "덜 읽어도" 된다는게 좋은것 같다

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,