기초/SPRING

[Spring] SpringBoot Security 구글 로그인 (react, nginx)

장동규 2022. 3. 27. 21:48

*표시는 배경지식

*인프런 강좌

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0/dashboard

 

[구성도]

더보기

Nginx 80 >> react 3000 로그인페이지 접속

react로그인에서 구글로그인 접속

구글 redi

구글로그인 이후 react 조회페이지로 이동

 

*Oauth2

 

applcation.yml Oauth2 추가

더보기

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: [id]
            client-secret: [pw]
            scope:
            - email
            - profile
            redirect-uri: http://localhost/login/oauth2/code/google

redirect주소를 nginx포트로 변경

 

SecurityConfig

public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	private PrincipalOauth2UserService principalOauth2UserService;
	
	@Bean
	public BCryptPasswordEncoder encodePassword() {
		return new BCryptPasswordEncoder();
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();
		http
			.authorizeRequests()
				.antMatchers("/user/**").authenticated()
				.anyRequest().permitAll()
				.and()
			.formLogin()
				.defaultSuccessUrl("/")
				.failureUrl("/login?error")
				.loginPage("/login")
				.loginProcessingUrl("/dologin")
				.and()
			.logout()
				.logoutSuccessUrl("/")
		        .deleteCookies("JSESSIONID")
				.logoutUrl("/dologout")
				.and()
			.oauth2Login()
				.loginPage("/login")
				.userInfoEndpoint()
				.userService(principalOauth2UserService);
	}
}

 

PrincipalDetails Class

public class PrincipalDetails implements OAuth2User{
	private static final long serialVersionUID = 1L;
	
	private UserInfo userInfo; // composition
	private Map<String, Object> attributes;
	
	public PrincipalDetails(UserInfo userInfo, Map<String, Object> attributes) {
		this.userInfo = userInfo;
		this.attributes = attributes;
	}
	
	//해당 User의 권한을 리턴하는 곳 
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		Collection<GrantedAuthority> collect = new ArrayList<>();
		collect.add(new GrantedAuthority() {
			
			@Override
			public String getAuthority() {
				return userInfo.getUserRole();
			}
		});
		return collect;
	}
    
	@Override
	public Map<String, Object> getAttributes() {
		// TODO Auto-generated method stub
		return this.attributes;
	}

	@Override
	public String getName() {	
		return null;
//		return this.attributes.get("sub").toString();
	}
}

 

PrincipalOauth2UserService Class

@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService{
	
	@Autowired
	private UserInfoRepository userInfoRepository; 
	
	@Override
	public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
		// TODO Auto-generated method stub
		
		OAuth2User oAuth2user = super.loadUser(userRequest);
		String provider = userRequest.getClientRegistration().getClientId(); //google
		String providerid = oAuth2user.getAttribute("sub"); // 12355657568678
		String username = provider+"_"+providerid; //google_123456678899
		String role = "ROLE_USER";
		
		UserInfo userInfo = userInfoRepository.findByInsUserName(username);
		if(userInfo == null) {
			userInfo = UserInfo.builder()
				.insUserName(username)
				.userRole(role)
				.provider(provider)
				.providerid(providerid)
				.build();
			userInfoRepository.save(userInfo);
		}
        
		return new PrincipalDetails(userInfo, oAuth2user.getAttributes());
	}
	
}

*UserInfo null체크를 통해 저장하는 로직은 사용자를 자동등록해주는 로직이다.

 

 

*react 구글요청

window.location.href = '/oauth2/authorization/google';

 

*nginx.conf

location = / {
        proxy_pass http://127.0.0.1:3000/;
}
location = /login {
        proxy_pass http://127.0.0.1:3000/;
}
location = /registry {
        proxy_pass http://127.0.0.1:3000/;
}

location ~ .static/(js|css|media)/(.+)$ {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location / {
    proxy_pass http://localhost:8081;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

react에서 페이지로 사용되는 location들은 절대경로로 지정

react build시 나오는 static / js,css,media파일들을 예외로 지정

나머지 경로를 Spring Boot 경로로 지정