Social Login - 코드 구현
Last updated
Last updated
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class OAuth2ClientConfig {
private final CustomOAuth2UserService customOAuth2UserService;
private final CustomOidcUserService customOidcUserService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(request -> request
.requestMatchers("/", "/css/**", "/js/**", "/images/**",
"/webjars/**", "/favicon.*", "/*/icon-*").permitAll() //정적 자원
.requestMatchers("/api/user").hasAnyRole("SCOPE_profile","SCOPE_email")
.requestMatchers("/api/oidc").hasAnyRole("SCOPE_openid") //OpenID를 지원하는 인가 서버만 허용
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig
// 커스텀한 OAuth2UserService 등록
.userService(customOAuth2UserService)
.oidcUserService(customOidcUserService)))
.logout(logout -> logout.logoutSuccessUrl("/"))
;
return http.build();
}
@Bean
public GrantedAuthoritiesMapper customAuthorityMapper() {
return new CustomAuthorityMapper();
}
}public class CustomAuthorityMapper implements GrantedAuthoritiesMapper {
private String prefix = "ROLE_";
@Override
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
HashSet<GrantedAuthority> mapped = new HashSet<>(authorities.size());
for (GrantedAuthority authority : authorities) {
if (authority instanceof OAuth2UserAuthority oAuth2UserAuthority) {
Map<String, Object> attributes = oAuth2UserAuthority.getAttributes();
//네이버의 경우 response 로 한번 감싸져 있다.
if (attributes.containsKey("response")) {
Map<String, Object> o = (Map<String, Object>) attributes.get("response");
for (String s : o.keySet()) {
mapped.add(mapAuthority("SCOPE_" + s));
}
}
}
mapped.add(mapAuthority(authority.getAuthority()));
}
return mapped;
}
private GrantedAuthority mapAuthority(String name) {
//구글의 스코프 정보 추출
if (name.lastIndexOf(".") > 0) {
int index = name.lastIndexOf(".");
name = "SCOPE_" + name.substring(index + 1);
}
if (!prefix.isEmpty() && !name.startsWith(prefix)) {
name = prefix + name;
}
return new SimpleGrantedAuthority(name);
}
}server:
port: 8081
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: {client_id}
client-secret: {client_secret}
redirect-uri: http://localhost:8081/login/oauth2/code/keycloak # /login/oauth2/code 는 스프링 시큐리티에서 정해놓은 기본값
client-name: oauth2-client-app
authorization-grant-type: authorization_code
client-authentication-method: client_secret_basic
scope:
- openid
- profile
provider: keycloak
google:
client-id: {client_id}
client-secret: {client_secret}
scope:
- openid
- profile
- email
naver:
client-id: {client_id}
client-secret: {client_secret}
authorization-grant-type: authorization_code
client-name: naver-client-app
redirect-uri: http://localhost:8081/login/oauth2/code/naver
scope:
- profile
- email
provider: naver
provider:
keycloak:
issuer-uri: http://localhost:8080/realms/oauth2
authorization-uri: http://localhost:8080/realms/oauth2/protocol/openid-connect/auth
token-uri: http://localhost:8080/realms/oauth2/protocol/openid-connect/token
user-info-uri: http://localhost:8080/realms/oauth2/protocol/openid-connect/userinfo
jwk-set-uri: http://localhost:8080/realms/oauth2/protocol/openid-connect/certs
user-name-attribute: preferred_username
naver:
authorization-uri: https://nid.naver.com/oauth2.0/authorize
token-uri: https://nid.naver.com/oauth2.0/token
user-info-uri: https://openapi.naver.com/v1/nid/me
user-name-attribute: response