본문 바로가기
개발/스프링 FIreBase Neo4j

Firebase, WebFlux Security, Spring 기본 설정드, 어노테이션 등

by 꿈트리꿈트리 2023. 1. 25.

사용되지 않는 함수

FirebaseOptions options = FirebaseOptions.builder()

new를 제거하고 B를 소문자로 변경해 주면 된다. 이게 인텔리제이가 다 한글로 나오는데 내가 설정한 건가 아니면 원래 그런 건가 메뉴까지 다 한글로 나오니 은근 불편하다는.

 

    @Bean
    public FirebaseApp firebaseApp() throws IOException {
        ClassPathResource classPathResource = new ClassPathResource("serviceAccountKey.json");

        FileInputStream serviceAccount =
                new FileInputStream(classPathResource.getFile());

        FirebaseOptions options = FirebaseOptions.builder()
                .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                .setDatabaseUrl("https:// {database-name} .firebaseio.com")
                .build();

        return FirebaseApp.initializeApp(options);
    }

    @Bean
    public FirebaseAuth getFirebaseAuth() throws IOException, FirebaseAuthException {
        FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp());
        
        Iterable<ExportedUserRecord> values = firebaseAuth.listUsers("1").getValues();
        values.forEach(a->{
            String uid = a.getUid();
            String displayName = a.getEmail();
            log.debug("uid {} / name : {}",uid, displayName);
        });
        return firebaseAuth;
    }

파이어베이스를 인스턴스화 시킬때 디비정보를 넣어주면 디비에 접속이 가능해진다

테스트로 uid와 이메일을 뿌려주는 소스다 잘 돌아간다.

이렇게 하면 잘 작동은 하나 자바 소스 수정 시 리로딩되면서 이미 파이어베이스 앱이 있다고 에러가 뜬다.

List<FirebaseApp> apps = FirebaseApp.getApps();
if (apps.isEmpty()) {
    ClassPathResource classPathResource = new ClassPathResource("serviceAccountKey.json");

    FileInputStream serviceAccount =
            new FileInputStream(classPathResource.getFile());

    FirebaseOptions options = FirebaseOptions.builder()
            .setCredentials(GoogleCredentials.fromStream(serviceAccount))
            .setDatabaseUrl("https://devkimchi-kaderra.firebaseio.com")
            .build();

    return FirebaseApp.initializeApp(options);
}
return FirebaseApp.getInstance();

앱이 비어 있는지를 테스트 해본 후 없으면 만들고 있으면 그것을 쓰는 부분을 추가했다.

 

이제는 firebase를 이용해 사용자가 로그인을 하고 권한을 이용할 수 있는지 해볼 예정이다.

 

1. WEBFLUX의 SPRING SECURITY 세팅

우선 WEBFLUX용 보안 설정을 한다

package devkimchi.kweb;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;

@Configuration
@EnableWebFluxSecurity
public class WebfluxSecurityConfig {
    @Bean
    public MapReactiveUserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("user")
                .password("easy1qaz")
                .roles("admin")
                .build();
        return new MapReactiveUserDetailsService(user);
    }
}

jwt 필터도 걸어줘야 할 것이고, 스프링 시큐리티의 초기 설정은 모든 페이지에 로그인이 되어야 하는데 이런 거 설정도 해주고 권한에 맞게 관리자만 볼 페이지 사용자 개인만 볼페이지등을 구분해 주기 위해 아주 간단한 보안 설정을 들어갑니다.

저 정도면 디비 없이도 관리자 정도는 암호를 걸어서 보안 처리를 해주고 아 그리고 너무 쉬운 비번을 해 놓으면 크롬 브라우저에서 계속 창을 띄우네요 귀찮으니 적당한 비밀번호 해주고 저장해 놓고 사용하시길.

알아둘 @Annotation

@DependsOn

- 먼저 초기화되도록 강제, 먼저 초기화되어야 할 메서드를 정해 줄 수 있다. 

@SneakyThrows

- Java에서 메서드 선언부에 Throws를 정의하지 않고도, 검사된 예외를 Throw 할 수 있도록 해준다 Lombok에서 제공

throws나 try catch가 귀찮아서 쓰는 경우가 있는데, 일어나지 않을 거 같은 예외 처리에 사용해 준다 고로 논란의 여지는 있으나 절대 일어나지 않을거 같은 경우에 사용하도록 주의를 기울이자.

@RequiredArgsConstructor

- final, nonnull 인 필드에 생성자 주입, di 여러 가지가 있으나 불변 객체를 만들어 준다. 불변 객체를 사용해야 하는 이유가 몇 가지 있는데 의존성을 주입해 주면서 불변 객체의 이점을 활용할 수 있게 해 준다 

 

@EnableReactiveMethodSecurity

@RequestMapping("/signin")
@PreAuthorize("isAuthenticated()")
public Mono<String> loginHtml() {
    log.debug("signin:::");
    log.debug("signin:::");
    log.debug("signin:::");
    return Mono.just("auth/login");
}

-리액티브 메서드 시큐리티를 활성화 시켜주면 메소드 단에서 preAuthorize 어노테이션으로 권한을 체크할 수 있다.

 

 

signin 페이지를 만들던 중 

<div th:replace="header::header"></div>

thymeleaf layout의 다른 html을 결합하는 부분이 있는데 전에는 잘 작동한 거 같은데 버전업 되면서 변한 건지 저 부분을

<div layout:fragment="header">
    <a th:href="@{/signin}">signin</a>
</div>

이렇게 하면 오류를 발생한다. fragment를 header로 줬는데 인식을 못하고 저 div를 header로 바꿔야 인식하는데 저 부분도 나중에 필수 기능이 잘 돌아가면 수정 보완해야 게다.

<header layout:fragment="header1">
    <a th:href="@{/signin}">signin</a>
</header>

이렇게 하면 정상 작동한다. fragment 이름 지정해 놓은 것에 상관없이 태그를 추적하는 거 같기도 하고.

하는 김에 종속성 설정 할 때 actuator도 설치해 주었는데 설치하고 아래 주소로 열

http://localhost:8082/actuator
{"_links":{"self":{"href":"http://localhost:8082/actuator","templated":false},"health":{"href":"http://localhost:8082/actuator/health","templated":false},"health-path":{"href":"http://localhost:8082/actuator/health/{*path}","templated":true}}}

이런 링크들을 알려주고

management:
  endpoints:
    web:
      exposure:
        include: "*"

application.yml 파일에 설정을 추가해주면

{"_links":{"self":{"href":"http://localhost:8082/actuator","templated":false},"beans":{"href":"http://localhost:8082/actuator/beans","templated":false},"caches-cache":{"href":"http://localhost:8082/actuator/caches/{cache}","templated":true},"caches":{"href":"http://localhost:8082/actuator/caches","templated":false},"health":{"href":"http://localhost:8082/actuator/health","templated":false},"health-path":{"href":"http://localhost:8082/actuator/health/{*path}","templated":true},"info":{"href":"http://localhost:8082/actuator/info","templated":false},"conditions":{"href":"http://localhost:8082/actuator/conditions","templated":false},"configprops":{"href":"http://localhost:8082/actuator/configprops","templated":false},"configprops-prefix":{"href":"http://localhost:8082/actuator/configprops/{prefix}","templated":true},"env":{"href":"http://localhost:8082/actuator/env","templated":false},"env-toMatch":{"href":"http://localhost:8082/actuator/env/{toMatch}","templated":true},"loggers":{"href":"http://localhost:8082/actuator/loggers","templated":false},"loggers-name":{"href":"http://localhost:8082/actuator/loggers/{name}","templated":true},"heapdump":{"href":"http://localhost:8082/actuator/heapdump","templated":false},"threaddump":{"href":"http://localhost:8082/actuator/threaddump","templated":false},"metrics-requiredMetricName":{"href":"http://localhost:8082/actuator/metrics/{requiredMetricName}","templated":true},"metrics":{"href":"http://localhost:8082/actuator/metrics","templated":false},"scheduledtasks":{"href":"http://localhost:8082/actuator/scheduledtasks","templated":false},"mappings":{"href":"http://localhost:8082/actuator/mappings","templated":false}}}
보다 많은 정보들을 볼 수 있는 링크를 제공한다.

 

관련 글:

https://devkimchi.tistory.com/69

 

IntellJ 필수 플러그인, Spring webFlux firebase admin

IntellJ 필수 플러그인 Lombok : 자바는 게터 세터를 만들일이 많은데 그런 작업을 자동화해준다. 이건 그냥 필수 Grep Console : 개발모드에선 로깅 수준을 Debug 모드로 쓰는데 로그가 많다 그런데 grep co

devkimchi.tistory.com