기존에 작성했던 코드에서 경로이름 및 파일이름과 설정파일 등등 수정된 부분이 많습니다.
참고해서 봐주세요
1. Application structure
2. API키 받아오기
http://www.wetoz.kr/html/board.php?bo_table=tipntech&wr_id=257&sca=API
위 경로를 참고해서 api키를 받아주세요
승인된 리디렉션 URI에 구글로그인 버튼을 눌렀을 경우 요청할 주소를 지정합니다.
3. application.properties 추가
## google login
google.client.clientId=<clientId>
google.client.clientSecret=<secretkey>
google.client.preEstablishedRedirectUri=http://localhost:8080/user/login/result
google.client.accessTokenUri=https://www.googleapis.com/oauth2/v4/token
google.client.userAuthorizationUri=https://accounts.google.com/o/oauth2/v2/auth
google.client.tokenName=oauth_token
google.client.authenticationScheme=query
google.client.clientAuthenticationScheme=form
google.client.scope=profile
google.resource.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo
## facebook login
facebook.client.clientId=<clientId>
facebook.client.clientSecret=<secretkey>
facebook.client.accessTokenUri=https://graph.facebook.com/oauth/access_token
facebook.client.userAuthorizationUri=https://www.facebook.com/dialog/oauth
facebook.client.tokenName=oauth_token
facebook.client.authenticationScheme=query
facebook.client.clientAuthenticationScheme=form
facebook.resource=userInfoUri: https://graph.facebook.com/me
<clientid> 와 <secretkey>부분에 발급받으신 키를 넣으시면됩니다.
4. OAuth2SuccessHandler 생성
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
//https://gs.saro.me/dev?tn=520
public class OAuth2SuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res, Authentication auth)
throws IOException, ServletException {
res.sendRedirect("/user/login/result");
}
}
소셜 로그인 성공시 다음경로로 이동시키는 핸들러입니다.
5. OAuth2Oauth2Filter생성
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.web.filter.CompositeFilter;
import com.security_blog.yg1110.handler.OAuth2SuccessHandler;
@EnableWebSecurity
@EnableOAuth2Client
public class Oauth2Filter {
@Autowired
OAuth2ClientContext oauth2ClientContext;
@Bean
@ConfigurationProperties("google.client")
OAuth2ProtectedResourceDetails googleclient() {
return new AuthorizationCodeResourceDetails();
}
@Bean
@ConfigurationProperties("google.resource")
ResourceServerProperties googleResource() {
return new ResourceServerProperties();
}
@Bean
@ConfigurationProperties("facebook.client")
OAuth2ProtectedResourceDetails facebookclient() {
return new AuthorizationCodeResourceDetails();
}
@Bean
@ConfigurationProperties("facebook.resource")
ResourceServerProperties facebookResource() {
return new ResourceServerProperties();
}
public Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter(
"/login/google");
OAuth2ClientAuthenticationProcessingFilter facebookFilter = new OAuth2ClientAuthenticationProcessingFilter(
"/login/facebook");
filters.add(ssoFilter("/login/google", googleFilter));
filters.add(ssoFilter("/login/facebook", facebookFilter));
filter.setFilters(filters);
return filter;
}
public Filter ssoFilter(String path, OAuth2ClientAuthenticationProcessingFilter Filter) {
ResourceServerProperties resource = null;
OAuth2ProtectedResourceDetails client = null;
if(path.equals("/login/google")) {
resource = googleResource();
client = googleclient();
}
else {
resource = facebookResource();
client = facebookclient();
}
OAuth2RestTemplate Template = new OAuth2RestTemplate(client, oauth2ClientContext);
Filter.setRestTemplate(Template);
Filter.setTokenServices(
new UserInfoTokenServices(resource.getUserInfoUri(), client.getClientId()));
Filter.setAuthenticationSuccessHandler(new OAuth2SuccessHandler());
return Filter;
}
@Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
}
properties에서 설정한 facebook과 google의 client와 resource정보를 가져와 사용합니다.
/login/google경로로 요청이 오게된다면 구글로그인 로직을 실행하고,
/login/facebook경로로 요청이 오게된다면 페이스북 로직을 실행합니다.
FilterRegistrationBean를 통해 다른 필터보다 우선순위를 올리기위해 -100을 주었습니다.
만약 로그인이 성공적으로 이루어졌을경우 위에서 만든 로그인 성공 핸들러를 타고 리다이렉션 되게됩니다.
6. SecurityConfig 수정
import javax.servlet.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.security_blog.yg1110.filter.Oauth2Filter;
import com.security_blog.yg1110.filter.jwt.JwtAuthenticationFilter;
import com.security_blog.yg1110.servicer.IUserService;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private IUserService userService;
@Autowired
private Oauth2Filter filter;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/login/css/**", "/login/js/**", "/login/images/**", "/login/vendor/**", "/login/fonts/**", "/ckeditor/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/user/admin/**").access("hasAuthority('ROLE_ADMIN')")
.antMatchers("/user/myinfo").access("hasAuthority('ROLE_USER')") // 페이지 권한 설정
.antMatchers("/user/signup", "/user/denied", "/user/logout/result", "/signup").permitAll().anyRequest()
.authenticated().and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class) // 소셜로그인 설정
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class) // jwt 필터 설정
.formLogin().loginPage("/user/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/user/login/result", true).permitAll() // 로그인 설정
.and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/user/logout")) // 로그아웃 설정
.logoutSuccessUrl("/user/logout/result").invalidateHttpSession(true).and().exceptionHandling()
.accessDeniedPage("/user/denied") // 403 예외처리 핸들링
.and().csrf().disable();
}
@Bean
public Filter ssoFilter() {
return filter.ssoFilter();
}
@Bean
public JwtAuthenticationFilter jwtFilter() {
return new JwtAuthenticationFilter();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(userService.passwordEncoder());
}
}
기존의 security정보에서 addFilterBefore를 이용하여 Oauth2Filter 필터를 추가합니다.
7. 결과화면
<a href="/login/facebook"></a>
<a href="/login/google"></a>
해당경로로 요청을 보내고
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<sec:authorize access="isAuthenticated()">
<sec:authentication property="principal" var="user" />
${user}
</sec:authorize>
다음과같이 요청을 출력해볼수 있습니다.
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OauthController {
@RequestMapping(value = "/social_uset_info", method = RequestMethod.GET)
public Object index() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println(auth.getDetails());
return auth;
}
}
스프링에서는 위와 같이 테스트해볼수 있습니다.
'Springboot' 카테고리의 다른 글
Springboot lucy-xss-filter 적용 (0) | 2020.03.11 |
---|---|
springboot email 인증 (0) | 2020.03.08 |
Springboot security (5) - jwt 적용 (0) | 2020.03.03 |
Springboot security (4) - Oauth2.0 (google) 적용 (0) | 2020.02.28 |
Springboot security (3) - 권한설정 (0) | 2020.02.26 |