웹개발/Spring Security

Spring Security 5-Google Login

RBWSN 2021. 9. 30. 17:04
728x90

 

今度にはoauth2を使用してGoogleLOGINを具現します。

まず、google api consoleで行きます。

そしてoauthの同意とUSERの認証を作ります。

 

 

 

 

 

そして、projectのmaven依存性を追加します。

 

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>

 

 

そして、

spring.security.oauth2.client.registration.google.client-id

とspring.security.oauth2.client.registration.google.client-secret

spring.security.oauth2.client.registration.google.scope=email,profile

にGoogleclientIDとpasswordを書きます。

 

 

そして、configを追加します。


.and()
                .oauth2Login()
                .loginPage("/loginform")
                .failureUrl("/loginform")
                .userInfoEndpoint()
                .userService(principalOauth2UserService)

 

 

そして、google loginをためにServiceを具現します。

package com.rbwsn.oauth;

import com.rbwsn.auth.SecurityDetails;
import com.rbwsn.constant.Role;
import com.rbwsn.controller.IndexController;
import com.rbwsn.entity.User;
import com.rbwsn.repository.UserRepository;
import com.rbwsn.service.UserService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.RequestDispatcher;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;

@Service
@Transactional
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;


    @SneakyThrows
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {


        OAuth2User oAuth2User = super.loadUser(userRequest);
        String provider = userRequest.getClientRegistration().getClientId();
        String providerId = oAuth2User.getAttribute("sub");
        String email = oAuth2User.getAttribute("email");
        String name = oAuth2User.getAttribute("name") + providerId;
        String password = passwordEncoder.encode("google1234");

        User user = userRepository.findByEmail(email);

        if (user == null) {
            user = User.builder()
                    .username(name)
                    .provider(provider)
                    .password(password)
                    .email(email)
                    .role(Role.ROLE_USER)
                    .provider_id(providerId)
                    .build();
            userRepository.save(user);
        }else{
            throw new IllegalStateException("aaa");
        }



        return new SecurityDetails(user, oAuth2User.getAttributes());
    }
}

 

password 와 DB저장을 위해 레파지토리와 패스워드 인코더를 받습니다.

AUtowired 받습니다.

 

그리고 Security에서는 세션의 정보로 OAuth2User 그리고 UserDetails만 받기 때문에

만약에 비교검사를해서 user정보를 SecurityDetails에 넘겨 주게 됩니다.

 

package com.rbwsn.auth;

//LOGINが終わったらSESSIONを作ります。

import com.rbwsn.entity.User;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

@Data
public class SecurityDetails implements UserDetails, OAuth2User {

    User user;
    private Map<String,Object> attributes;


    public SecurityDetails(User user){
        this.user=user;
    }

    public SecurityDetails(User user, Map<String,Object> attributes){
        this.user=user;
        this.attributes = attributes;
    }

    //権限をReturn
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collection = new ArrayList<>();
        collection.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole().toString();
            }
        });
        return collection;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public <A> A getAttribute(String name) {
        return null;
    }

    @Override
    public Map<String, Object> getAttributes() {
        return attributes;
    }

    @Override
    public String getName() {
        return null;
    }
}

 

ここではGoogleの情報はMap<String,Object> 形式ですから、新しい生成します。

 

Controllerには

@GetMapping("/user")
    public @ResponseBody String user(@AuthenticationPrincipal SecurityDetails securityDetails){
        System.out.println("prin:"+ securityDetails.getUser().toString());
        return "user";
    }

@AuthenticationPrincipalを私が生成したCLASSにDIします。

 

728x90