{"id":241,"date":"2020-03-21T20:08:37","date_gmt":"2020-03-21T11:08:37","guid":{"rendered":"http:\/\/www.skyer9.pe.kr\/wordpress\/?p=241"},"modified":"2020-03-28T18:04:51","modified_gmt":"2020-03-28T09:04:51","slug":"from-hello-to-querydsl-google-naver-login-10-12","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=241","title":{"rendered":"[From Hello To QueryDSL] Google\/Naver Login (10\/12)"},"content":{"rendered":"<h1>Google\/Naver Login<\/h1>\n<h2>\uac1c\ubc1c\ud658\uacbd<\/h2>\n<ul>\n<li>Spring Boot 2.1.x<\/li>\n<li>Gradle 4.10.2<\/li>\n<\/ul>\n<h2>build.gradle \uc218\uc815<\/h2>\n<p>build.gradle<\/p>\n<pre><code class=\"language-configuration\">......\ndependencies {\n    \/\/ ......\n    compile(&#039;org.springframework.boot:spring-boot-starter-oauth2-client&#039;)\n    \/\/ ......\n}\n......<\/code><\/pre>\n<h2>\ud30c\uc77c \uc218\uc815 \ubc0f \ucd94\uac00<\/h2>\n<p>src\/main\/java\/kr\/co\/episode\/example\/config\/oauth2\/dto\/OAuthAttributes.java<\/p>\n<pre><code class=\"language-java\">@Getter\npublic class OAuthAttributes {\n\n    private Map&lt;String, Object&gt; attributes;\n    private String nameAttributeKey;\n    private String name;\n    private String email;\n    private String picture;\n\n    @Builder\n    public OAuthAttributes(Map&lt;String, Object&gt; attributes, String nameAttributeKey, String name, String email, String picture) {\n        this.attributes = attributes;\n        this.nameAttributeKey = nameAttributeKey;\n        this.name = name;\n        this.email = email;\n        this.picture = picture;\n    }\n\n    public static OAuthAttributes of(String registrationId, String userNameAttributeName, Map&lt;String, Object&gt; attributes) {\n        \/\/System.out.println(attributes);\n        if(&quot;naver&quot;.equals(registrationId)) {\n            return ofNaver(&quot;id&quot;, attributes);\n        }\n\n        return ofGoogle(userNameAttributeName, attributes);\n    }\n\n    private static OAuthAttributes ofGoogle(String userNameAttributeName, Map&lt;String, Object&gt; attributes) {\n        return OAuthAttributes.builder()\n                .name((String) attributes.get(&quot;name&quot;))\n                .email((String) attributes.get(&quot;email&quot;))\n                .picture((String) attributes.get(&quot;picture&quot;))\n                .attributes(attributes)\n                .nameAttributeKey(userNameAttributeName)\n                .build();\n    }\n\n    private static OAuthAttributes ofNaver(String userNameAttributeName, Map&lt;String, Object&gt; attributes) {\n        Map&lt;String, Object&gt; response = (Map&lt;String, Object&gt;) attributes.get(&quot;response&quot;);\n\n        return OAuthAttributes.builder()\n                .name((String) response.get(&quot;name&quot;))\n                .email((String) response.get(&quot;email&quot;))\n                .picture((String) response.get(&quot;profile_image&quot;))\n                .attributes(response)\n                .nameAttributeKey(userNameAttributeName)\n                .build();\n    }\n\n    public User toEntity() {\n        return User.builder()\n                .name(name)\n                .email(email)\n                .picture(picture)\n                \/\/.role(Role.GUEST)\n                .role(Role.USER)\n                .build();\n    }\n}<\/code><\/pre>\n<p>src\/main\/java\/kr\/co\/episode\/example\/config\/oauth2\/CustomOAuth2UserService.java<\/p>\n<pre><code class=\"language-java\">@RequiredArgsConstructor\n@Service\npublic class CustomOAuth2UserService implements OAuth2UserService&lt;OAuth2UserRequest, OAuth2User&gt; {\n\n    private final UserRepository userRepository;\n    private final HttpSession httpSession;\n\n    @Override\n    public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {\n        OAuth2UserService oAuth2UserService = new DefaultOAuth2UserService();\n        OAuth2User oAuth2User = oAuth2UserService.loadUser(oAuth2UserRequest);\n\n        String registrationId = oAuth2UserRequest.getClientRegistration().getRegistrationId();\n        String userNameAttributeName = oAuth2UserRequest.getClientRegistration().getProviderDetails()\n                .getUserInfoEndpoint().getUserNameAttributeName();\n\n        OAuthAttributes attributes = OAuthAttributes.\n                of(registrationId, userNameAttributeName, oAuth2User.getAttributes());\n\n        User user = saveOrUpdate(attributes);\n\n        httpSession.setAttribute(&quot;user&quot;, new SessionUserDto(user));\n\n        return new DefaultOAuth2User(\n                Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),\n                attributes.getAttributes(),\n                attributes.getNameAttributeKey()\n        );\n    }\n\n    private User saveOrUpdate(OAuthAttributes attributes) {\n        User user = userRepository.findByEmail(attributes.getEmail())\n                .map(entity -&gt; entity.update(attributes.getName(), attributes.getPicture()))\n                .orElse(attributes.toEntity());\n\n        return userRepository.save(user);\n    }\n}<\/code><\/pre>\n<p>src\/main\/java\/kr\/co\/episode\/example\/config\/SecurityConfig.java<\/p>\n<pre><code class=\"language-java\">@RequiredArgsConstructor\n@EnableWebSecurity\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n\n    private final CustomOAuth2UserService customOAuth2UserService;\n\n    @Override\n    protected void configure(HttpSecurity httpSecurity) throws Exception {\n        httpSecurity.csrf().disable()\n                .headers().frameOptions().disable()\n                .and()\n                    .authorizeRequests()\n                    .antMatchers(&quot;\/&quot;, &quot;\/css\/**&quot;, &quot;\/images\/**&quot;, &quot;\/js\/**&quot;, &quot;\/oauth_login&quot;, &quot;\/profile&quot;).permitAll()\n                    .antMatchers(&quot;\/api\/v1\/**&quot;, &quot;\/posts\/save&quot;).hasRole(Role.USER.name())\n                    .anyRequest().authenticated()\n                .and()\n                    .logout()\n                    .logoutSuccessUrl(&quot;\/&quot;)\n                .and()\n                    .oauth2Login()\n                    .loginPage(&quot;\/oauth_login&quot;)\n                    .userInfoEndpoint()\n                    .userService(customOAuth2UserService);\n    }\n}<\/code><\/pre>\n<p>src\/main\/resources\/application.properties<\/p>\n<pre><code class=\"language-configuration\">spring.security.oauth2.client.registration.google.client-id=\nspring.security.oauth2.client.registration.google.client-secret=\nspring.security.oauth2.client.registration.google.scope=profile,email\n\n# registration\nspring.security.oauth2.client.registration.naver.client-id=\nspring.security.oauth2.client.registration.naver.client-secret=\nspring.security.oauth2.client.registration.naver.scope=name,email,profile_image\nspring.security.oauth2.client.registration.naver.redirect-uri={baseUrl}\/{action}\/oauth2\/code\/{registrationId}\nspring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code\nspring.security.oauth2.client.registration.naver.client-name=Naver\n\n# provider\nspring.security.oauth2.client.provider.naver.authorization-uri=https:\/\/nid.naver.com\/oauth2.0\/authorize\nspring.security.oauth2.client.provider.naver.token-uri=https:\/\/nid.naver.com\/oauth2.0\/token\nspring.security.oauth2.client.provider.naver.user-info-uri=https:\/\/openapi.naver.com\/v1\/nid\/me\nspring.security.oauth2.client.provider.naver.user-name-attribute=response<\/code><\/pre>\n<p>src\/main\/resources\/templates\/oauth_login.html<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html xmlns:th=&quot;http:\/\/www.thymeleaf.org&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;title&gt;\uac8c\uc2dc\ud310&lt;\/title&gt;\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.2\/css\/bootstrap.min.css&quot;&gt;\n    &lt;style&gt;\n        .container p { display: inline }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body class=&quot;container&quot;&gt;\n\n&lt;h3&gt;\ub85c\uadf8\uc778:&lt;\/h3&gt;\n\n&lt;div class=&quot;col-md-12&quot;&gt;\n    &lt;div class=&quot;row&quot;&gt;\n        &lt;div class=&quot;col-md-6&quot;&gt;\n            &lt;a th:each=&quot;url : ${urls}&quot; th:href=&quot;${url.link}&quot; class=&quot;btn btn-success active&quot; role=&quot;button&quot; th:text=&quot;${url.client}&quot;&gt;&lt;\/a&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n&lt;script src=&quot;https:\/\/code.jquery.com\/jquery-3.3.1.min.js&quot;&gt;&lt;\/script&gt;\n&lt;script src=&quot;https:\/\/stackpath.bootstrapcdn.com\/bootstrap\/4.3.1\/js\/bootstrap.min.js&quot;&gt;&lt;\/script&gt;\n\n&lt;script src=&quot;\/js\/app\/index.js&quot;&gt;&lt;\/script&gt;\n\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n<p>src\/main\/java\/kr\/co\/episode\/example\/web\/dto\/LoginUrlDto.java<\/p>\n<pre><code class=\"language-java\">@Getter\npublic class LoginUrlDto {\n\n    private String client;\n    private String url;\n\n    public String getLink() {\n        return &quot;\/&quot; + url;\n    }\n\n    public LoginUrlDto(String client, String url) {\n        this.client = client;\n        this.url = url;\n    }\n}<\/code><\/pre>\n<p>src\/main\/resources\/templates\/index.html<\/p>\n<pre><code class=\"language-html\">&lt;h1&gt;\uc2a4\ud504\ub9c1 \ubd80\ud2b8 \uac8c\uc2dc\ud310&lt;\/h1&gt;\n\n&lt;div class=&quot;col-md-12&quot;&gt;\n    &lt;div class=&quot;row&quot;&gt;\n        &lt;div class=&quot;col-md-6&quot;&gt;\n            &lt;a href=&quot;\/posts\/save&quot; role=&quot;button&quot; class=&quot;btn&quot; btn-primary&gt;\uae00 \ub4f1\ub85d&lt;\/a&gt;\n            &lt;div th:if=&quot;${userName != null}&quot; th:inline=&quot;text&quot;&gt;\n                [[${userName}]] \ub2d8, \uc548\ub155\ud558\uc138\uc694.\n                &lt;a href=&quot;\/logout&quot; class=&quot;btn btn-info active&quot; role=&quot;button&quot;&gt;\ub85c\uadf8\uc544\uc6c3&lt;\/a&gt;\n            &lt;\/div&gt;\n            &lt;div th:if=&quot;${userName == null}&quot;&gt;\n                &lt;a href=&quot;\/oauth2\/authorization\/google&quot; class=&quot;btn btn-success active&quot; role=&quot;button&quot;&gt;\uad6c\uae00 \ub85c\uadf8\uc778&lt;\/a&gt;\n                &lt;a href=&quot;\/oauth2\/authorization\/naver&quot; class=&quot;btn btn-success active&quot; role=&quot;button&quot;&gt;\ub124\uc774\ubc84 \ub85c\uadf8\uc778&lt;\/a&gt;\n            &lt;\/div&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n&lt;div style=&quot;height: 80px;&quot;&gt;\n\n&lt;\/div&gt;<\/code><\/pre>\n<p>src\/main\/java\/kr\/co\/episode\/example\/web\/LoginController.java<\/p>\n<pre><code class=\"language-java\">@Controller\npublic class LoginController {\n\n    private static String authorizationRequestBaseUri = &quot;oauth2\/authorization&quot;;\n    List&lt;LoginUrlDto&gt; oauth2AuthenticationUrls;\n\n    @Autowired\n    private ClientRegistrationRepository clientRegistrationRepository;\n\n    @GetMapping(&quot;\/oauth_login&quot;)\n    public String getLoginPage(Model model) {\n        if (oauth2AuthenticationUrls == null) {\n            oauth2AuthenticationUrls = new ArrayList();\n\n            Iterable&lt;ClientRegistration&gt; clientRegistrations = null;\n            ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class);\n            if (type != ResolvableType.NONE &amp;&amp; ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {\n                clientRegistrations = (Iterable&lt;ClientRegistration&gt;) clientRegistrationRepository;\n\n                clientRegistrations.forEach(registration -&gt;\n                        oauth2AuthenticationUrls.add(new LoginUrlDto(registration.getClientName(), authorizationRequestBaseUri + &quot;\/&quot; + registration.getRegistrationId()))\n                );\n            }\n        }\n\n        model.addAttribute(&quot;urls&quot;, oauth2AuthenticationUrls);\n\n        return &quot;oauth_login&quot;;\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Google\/Naver Oauth2 Login \uae30\ub2a5\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-241","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-1"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=241"}],"version-history":[{"count":5,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/241\/revisions"}],"predecessor-version":[{"id":336,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/241\/revisions\/336"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}