facebook test
This commit is contained in:
@@ -24,6 +24,9 @@ ext {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile('org.springframework.security:spring-security-oauth2-client')
|
||||
compile('org.springframework.security:spring-security-oauth2-jose')
|
||||
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
package io.bluemoon.authorizationserver.config;
|
||||
|
||||
import io.bluemoon.authorizationserver.domain.social.UserArgumentResolver;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.web.filter.ForwardedHeaderFilter;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@EnableWebSecurity
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private UserArgumentResolver userArgumentResolver;
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
resolvers.add(userArgumentResolver);
|
||||
}
|
||||
|
||||
@Bean
|
||||
FilterRegistrationBean forwardedHeaderFilter() {
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
package io.bluemoon.authorizationserver.config;
|
||||
|
||||
import io.bluemoon.authorizationserver.domain.social.ClientResources;
|
||||
import io.bluemoon.authorizationserver.service.user.CustomUserDetailsServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -16,28 +11,18 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.oauth2.client.OAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.csrf.CsrfFilter;
|
||||
import org.springframework.web.filter.CharacterEncodingFilter;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
//@Order(SecurityProperties.BASIC_AUTH_ORDER - 6)
|
||||
@EnableOAuth2Client
|
||||
@Order(-1)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private CustomUserDetailsServiceImpl customUserDetailsService;
|
||||
|
||||
@Qualifier("oauth2ClientContext")
|
||||
@Autowired
|
||||
private OAuth2ClientContext oAuth2ClientContext;
|
||||
|
||||
public WebSecurityConfig(
|
||||
CustomUserDetailsServiceImpl customUserDetailsService
|
||||
) {
|
||||
@@ -63,8 +48,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/", "/login/**", "/css/**", "/images/**", "/js/**",
|
||||
"/console/**").permitAll()
|
||||
"/console/**", "/oauth2/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.oauth2Login()
|
||||
.defaultSuccessUrl("/loginSuccess")
|
||||
.failureUrl("/loginFailure")
|
||||
.and()
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
@@ -78,8 +67,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.deleteCookies("JSESSSIONID")
|
||||
.invalidateHttpSession(true)
|
||||
.and()
|
||||
.addFilterBefore(filter, CsrfFilter.class)
|
||||
.csrf().disable();
|
||||
.addFilterBefore(filter, CsrfFilter.class);
|
||||
// .csrf().disable();
|
||||
// http.formLogin().loginPage("/login").permitAll()
|
||||
// .and()
|
||||
// .requestMatchers().antMatchers("/login", "/logout", "/oauth/authorize", "/oauth/confirm_access")
|
||||
@@ -121,12 +110,42 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
|
||||
// social login
|
||||
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("facebook")
|
||||
public ClientResources facebook() {
|
||||
return new ClientResources();
|
||||
}
|
||||
// @Bean
|
||||
// public FilterRegistrationBean oauth2ClientFilterRegistration(
|
||||
// OAuth2ClientContextFilter filter
|
||||
// ) {
|
||||
// FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
// registration.setFilter(new ForwardedHeaderFilter());
|
||||
// registration.setFilter(filter);
|
||||
// registration.setOrder(-100);
|
||||
// return registration;
|
||||
// }
|
||||
//
|
||||
// private Filter oauth2Filter() {
|
||||
// CompositeFilter filter = new CompositeFilter();
|
||||
// List<Filter> filters = new ArrayList<>();
|
||||
// filters.add(oauth2Filter(facebook(), "/login/facebook", SocialType.FACEBOOK));
|
||||
//
|
||||
// filter.setFilters(filters);
|
||||
// return filter;
|
||||
// }
|
||||
//
|
||||
// private Filter oauth2Filter(ClientResources client, String path, SocialType socialType) {
|
||||
// OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(path);
|
||||
// OAuth2RestTemplate template = new OAuth2RestTemplate(client.getClient(), oAuth2ClientContext);
|
||||
// filter.setRestTemplate(template);
|
||||
// filter.setTokenServices(new UserTokenService(client, socialType));
|
||||
// filter.setAuthenticationSuccessHandler((request, response, authentication) ->
|
||||
// response.sendRedirect("/" + socialType.getVaule() + "/complete"));
|
||||
// filter.setAuthenticationFailureHandler((request, response, exception) ->
|
||||
// response.sendRedirect("/error"));
|
||||
// return filter;
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// @ConfigurationProperties("facebook")
|
||||
// public ClientResources facebook() {
|
||||
// return new ClientResources();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.bluemoon.authorizationserver.config.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SocialUser {
|
||||
|
||||
}
|
||||
@@ -1,17 +1,23 @@
|
||||
package io.bluemoon.authorizationserver.controller.sso;
|
||||
|
||||
import io.bluemoon.authorizationserver.config.annotation.SocialUser;
|
||||
import io.bluemoon.authorizationserver.domain.UserResponseWrapper;
|
||||
import io.bluemoon.authorizationserver.domain.oauth.accesstoken.AccessToken;
|
||||
import io.bluemoon.authorizationserver.domain.social.SocialType;
|
||||
import io.bluemoon.authorizationserver.domain.user.User;
|
||||
import io.bluemoon.authorizationserver.service.sso.SsoService;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.security.Principal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
public class SsoController {
|
||||
@@ -75,4 +81,34 @@ public class SsoController {
|
||||
return user;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/loginSuccess")
|
||||
public String loginComplete(@SocialUser User user) {
|
||||
return "redirect:/login/success";
|
||||
}
|
||||
|
||||
@GetMapping(value = "/login/success")
|
||||
@ResponseBody
|
||||
public String test2() {
|
||||
return "kkk";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// @GetMapping(value = "/{facebook|google|kakao}/complete")
|
||||
// public String loginComplete(HttpSession session) {
|
||||
// OAuth2Authentication authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
|
||||
// Map<String, String> map = (HashMap<String, String>) authentication.getUserAuthentication().getDetails();
|
||||
// session.setAttribute("user", User.builder()
|
||||
// .username(map.get("username"))
|
||||
// .email(map.get("email"))
|
||||
// .principal(map.get("id"))
|
||||
// .socialType(SocialType.FACEBOOK)
|
||||
// .createdAt(LocalDateTime.now())
|
||||
// .updatedAt(LocalDateTime.now())
|
||||
// .build()
|
||||
// );
|
||||
// return "redirect:/";
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package io.bluemoon.authorizationserver.domain.social;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||
|
||||
public class ClientResources {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private ResourceServerProperties resource = new ResourceServerProperties();
|
||||
|
||||
public AuthorizationCodeResourceDetails getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
private ResourceServerProperties getResource() {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
//package io.bluemoon.authorizationserver.domain.social;
|
||||
//
|
||||
//import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
||||
//import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
//import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||
//
|
||||
//public class ClientResources {
|
||||
//
|
||||
// @NestedConfigurationProperty
|
||||
// private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
|
||||
//
|
||||
// @NestedConfigurationProperty
|
||||
// private ResourceServerProperties resource = new ResourceServerProperties();
|
||||
//
|
||||
// public AuthorizationCodeResourceDetails getClient() {
|
||||
// return client;
|
||||
// }
|
||||
//
|
||||
// public ResourceServerProperties getResource() {
|
||||
// return resource;
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package io.bluemoon.authorizationserver.domain.social;
|
||||
|
||||
import io.bluemoon.authorizationserver.config.annotation.SocialUser;
|
||||
import io.bluemoon.authorizationserver.domain.user.User;
|
||||
import io.bluemoon.authorizationserver.domain.user.UserRepository;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private UserRepository userRepository;
|
||||
|
||||
public UserArgumentResolver(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return parameter.getParameterAnnotation(SocialUser.class) != null &&
|
||||
parameter.getParameterType().equals(User.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
HttpSession session = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getSession();
|
||||
User user = (User) session.getAttribute("user");
|
||||
return getUser(user, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증된 User 객체를 만드는 메인 메서드
|
||||
* @param user
|
||||
* @param session
|
||||
* @return
|
||||
*/
|
||||
private User getUser(User user, HttpSession session) {
|
||||
// 세션에서 가져온 유저가 널일 경우에만
|
||||
System.out.println("-------------------------------------");
|
||||
System.out.println(user);
|
||||
if (user == null) {
|
||||
try {
|
||||
// OAuth2Authentication authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
|
||||
// Map<String, String> map = (HashMap<String, String>) authentication.getUserAuthentication().getDetails();
|
||||
// User convertUser = convertUser(String.valueOf(authentication.getAuthorities().toArray()[0]), map);
|
||||
OAuth2AuthenticationToken authentication = (OAuth2AuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
|
||||
Map<String, Object> map = authentication.getPrincipal().getAttributes();
|
||||
User convertUser = convertUser(authentication.getAuthorizedClientRegistrationId(), map);
|
||||
|
||||
user = userRepository.findByEmail(convertUser.getEmail());
|
||||
if (user == null) {
|
||||
user = userRepository.save(convertUser);
|
||||
}
|
||||
setRoleIfNotSame(user, authentication, map);
|
||||
session.setAttribute("user", user);
|
||||
} catch (ClassCastException e) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
System.out.println(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 인증된 소셜 미디어 타입에 따라 빌더를 사용하여 User 객체를 만들어 주는 가교 역할
|
||||
* @param authority
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
private User convertUser(String authority, Map<String, Object> map) {
|
||||
if (SocialType.FACEBOOK.getVaule().equals(authority)) return getModernUser(SocialType.FACEBOOK, map);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이스북이나 구글 같이 공통되는 명명규칙을 가진 그룹을 맵핑
|
||||
* @param socialType
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
private User getModernUser(SocialType socialType, Map<String, Object> map) {
|
||||
return User.builder()
|
||||
.username(String.valueOf(map.get("name")))
|
||||
.email(String.valueOf(map.get("mail")))
|
||||
.principal(String.valueOf(map.get("id")))
|
||||
.socialType(socialType)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.updatedAt(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증된 authentication이 권한을 갖고 있는지 체크하는 용도
|
||||
* 만약 저장된 User 권한이 없으면 SecurityContextHolder를 사용하여 해당 소셜미디어 타입으로 권한을 저장
|
||||
* @param user
|
||||
* @param authentication
|
||||
* @param map
|
||||
*/
|
||||
private void setRoleIfNotSame(User user, OAuth2AuthenticationToken authentication, Map<String, Object> map) {
|
||||
if (!authentication.getAuthorities().contains(
|
||||
new SimpleGrantedAuthority(user.getSocialType().getRoleType()))) {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(map, "N/A", AuthorityUtils.createAuthorityList(user.getSocialType().getRoleType()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//package io.bluemoon.authorizationserver.domain.social;
|
||||
//
|
||||
//import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor;
|
||||
//import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices;
|
||||
//import org.springframework.security.core.GrantedAuthority;
|
||||
//import org.springframework.security.core.authority.AuthorityUtils;
|
||||
//
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//
|
||||
//public class UserTokenService extends UserInfoTokenServices {
|
||||
// public UserTokenService(ClientResources resources, SocialType socialType) {
|
||||
// super(resources.getResource().getUserInfoUri(), resources.getClient().getClientId());
|
||||
//
|
||||
// setAuthoritiesExtractor(new OAuth2AuthoritiesExtractor(socialType));
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public static class OAuth2AuthoritiesExtractor implements AuthoritiesExtractor {
|
||||
// private String socialType;
|
||||
//
|
||||
// public OAuth2AuthoritiesExtractor(SocialType socialType) {
|
||||
// this.socialType = socialType.getRoleType();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<GrantedAuthority> extractAuthorities(Map<String, Object> map) {
|
||||
// return AuthorityUtils.createAuthorityList(this.socialType);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -21,9 +21,9 @@ public class UserDetail implements UserDetails {
|
||||
|
||||
public UserDetail(User user) {
|
||||
this.id = user.getId();
|
||||
this.username = user.getUserName();
|
||||
this.username = user.getUsername();
|
||||
this.password = user.getPassword();
|
||||
this.userType = user.getUserType();
|
||||
// this.userType = user.getSocialType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,5 +4,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
User findByUserName(String userName);
|
||||
User findByUsername(String username);
|
||||
User findByEmail(String email);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class CustomUserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
User user = userRepository.findByUserName(username);
|
||||
User user = userRepository.findByUsername(username);
|
||||
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException("UsernameNotFound[" + username + "]");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server.port=8081
|
||||
server.servlet.context-path=/mk-auth
|
||||
#server.servlet.context-path=/mk-auth
|
||||
server.use-forward-headers=false
|
||||
|
||||
security.oauth2.authorization.check-token-access=isAuthenticated()
|
||||
@@ -18,12 +18,16 @@ spring.jpa.show-sql=true
|
||||
#spring.jpa.generate-ddl=false
|
||||
#spring.jpa.hibernate.ddl-auto=none
|
||||
|
||||
facebook.client.client-id=1684497291764010
|
||||
facebook.client.client-secret=cfefbfbb6ca436828f197df32d85b861
|
||||
facebook.client.access-token-uri=https://graph.facebook.com/oauth/access_token
|
||||
facebook.client.user-authorization-uri=https://www.facebook.com/dialog/oauth
|
||||
facebook.client.token-name=oauth_token
|
||||
facebook.client.authentication-scheme=query
|
||||
facebook.client.client-authentication-scheme=form
|
||||
spring.security.oauth2.client.registration.facebook.client-id=715358882216622
|
||||
spring.security.oauth2.client.registration.facebook.client-secret=a39d8f1e06e8c3863d12e8461f4991e8
|
||||
#facebook.client.access-token-uri=https://graph.facebook.com/oauth/access_token
|
||||
#facebook.client.user-authorization-uri=https://www.facebook.com/dialog/oauth
|
||||
#facebook.client.token-name=oauth_token
|
||||
#facebook.client.authentication-scheme=query
|
||||
#facebook.client.client-authentication-scheme=form
|
||||
#
|
||||
#facebook.resource.user-info-uri=https://graph.facebook.com/me?fields=id
|
||||
|
||||
facebook.resource.user-info-uri=https://graph.facebook.com/me
|
||||
|
||||
logging.level.web=debug
|
||||
spring.http.log-request-details=true
|
||||
@@ -16,5 +16,9 @@
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a class="facebook-login-text" href="/oauth2/authorization/facebook">facebook으로 로그인</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user