JavaRush /Java Blog /Random-KO /Notes 서비스의 예를 사용하여 이메일과 OAuth2를 통한 일반 로그인을 Spring Securit...

Notes 서비스의 예를 사용하여 이메일과 OAuth2를 통한 일반 로그인을 Spring Security에 도입해 보겠습니다.

Random-KO 그룹에 게시되었습니다
신청서를 작성하는 동안 사용자가 이메일과 소셜 네트워크를 통해 등록하도록 하는 방법에 대한 명확한 기사가 부족한 상황에 직면했습니다. 클래식 로그인 양식 설정에 대한 좋은 튜토리얼이 있었습니다. OAuth2 에 대한 좋은 튜토리얼이 있었습니다 . 두 가지 방법을 결합하는 방법에 대한 정보는 범죄적으로 거의 없었습니다. 검색 과정에서 우리는 실행 가능한 솔루션을 찾을 수 있었습니다. 그것은 궁극적인 진리라고 주장하지 않지만 그 기능을 수행합니다. 이 기사에서는 유사한 Spring Security 구성을 사용하여 처음부터 노트 스토리지 서비스를 구현하는 방법을 보여 드리겠습니다. Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 1참고: 저장소, 컨트롤러 등에 대한 자세한 설명 없이 Spring 보안에만 관심이 집중될 것이기 때문에 독자가 Spring에 대해 최소한 두 개의 튜토리얼을 완료했다면 좋습니다. 그렇지 않으면 이미 꽤 큰 기사가 다음과 같이 될 것입니다. 거대해지다. 콘텐츠
  1. 프로젝트 만들기
  2. 엔터티 및 애플리케이션 로직 생성
    1. 엔터티
    2. 저장소
    3. 컨트롤러
    4. 페이지
  3. 클래식 로그인을 위한 Spring Security 구성
    1. 기본 구성 SecurityConfig
    2. 사용자 정의 사용자 로그인
    3. 컨트롤러를 개선해보자
    4. 시작하다
  4. Spring Security의 예로 Google을 사용하여 OAuth2 설정
    1. 필터 구성 및 application.properties
    2. Google Cloud Platform에 애플리케이션 등록의 주요 사항
    3. CustomUserInfoTokenServices
  5. 프로젝트의 최종 출시

프로젝트 만들기

start.spring.io 로 이동하여 프로젝트의 기초를 형성합니다.
  • 웹 - 내장된 Tomcat에서 애플리케이션 실행, URL 매핑 등
  • JPA - 데이터베이스 연결;
  • Mustache는 웹페이지를 생성하는 데 사용되는 템플릿 엔진입니다.
  • 보안 - 애플리케이션 보호. 이것이 이 글이 작성된 이유입니다.
결과 아카이브를 다운로드하고 필요한 폴더에 압축을 풉니다. IDE에서 실행합니다. 귀하의 재량에 따라 데이터베이스를 선택할 수 있습니다. 저는 프로젝트의 데이터베이스로 MySQL을 사용하므로 <dependent> 블록의 pom.xml 파일에 다음 종속성을 추가합니다.
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.34</version>
</dependency>
application.properties 구성은 현재 다음과 같습니다.
spring.datasource.url=jdbc:mysql://localhost:3306/springsectut?createDatabaseIfNotExist=true&useSSL=false&autoReconnect=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=yourUsername
spring.datasource.password=yourPassword

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.connection.characterEncoding=utf-8
spring.jpa.properties.connection.CharSet=utf-8
spring.jpa.properties.connection.useUnicode=true

spring.mustache.expose-request-attributes=true

엔터티 및 애플리케이션 로직 생성

엔터티

entities데이터베이스 엔터티를 배치할 패키지를 만들어 보겠습니다 . 사용자는 Spring Security 구성에 필요한 User인터페이스를 구현하는 클래스로 설명됩니다 . UserDetails사용자는 ID, 사용자 이름(이메일), 비밀번호, 이름, 역할, 활동 플래그, Google 계정 이름 및 이메일( googleNamegoogleUsername)을 갖게 됩니다.
@Entity
@Table(name = "user")
public class User implements UserDetails
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String username;
  private String password;
  private String name;
  private boolean active;
  private String googleName;
  private String googleUsername;

  @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
  @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
  @Enumerated(EnumType.STRING)
  private Set<Role> roles;

    //Геттеры, сеттеры, toString(), equals(), hashcode(), имплементация UserDetails
}
사용자 역할은 Spring Security의 액세스를 규제하는 데 사용됩니다. 우리 애플리케이션은 하나의 역할만 사용합니다:
public enum Role implements GrantedAuthority
{
  USER;

  @Override
  public String getAuthority()
  {
     return name();
  }
}
ID, 노트 제목, 노트 본문 및 해당 노트가 속한 사용자의 ID를 사용하여 노트 클래스를 생성해 보겠습니다.
@Entity
@Table(name = "note")
public class Note
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String title;
  private String note;
  private Long userId;

    //Геттеры, сеттеры, toString(), equals(), hashcode()
}

저장소

엔터티를 데이터베이스에 저장하려면 모든 더러운 작업을 수행할 저장소가 필요합니다. 패키지를 생성해 보겠습니다 . 그 안에 인터페이스에서 상속된 repos인터페이스를 생성하겠습니다 . UserRepoNoteRepoJpaRepository<Entity, Id>
@Service
@Repository
public interface UserRepo extends JpaRepository<User, Long>
{}

@Service
@Repository
public interface NoteRepo extends JpaRepository<Note, Long>
{
  List<Note> findByUserId(Long userId);
}

컨트롤러

우리의 메모 서비스에는 다음 페이지가 있습니다:
  • 집;
  • 등록;
  • 입구;
  • 사용자 메모 목록입니다.
승인된 사용자만이 메모 목록에 접근할 수 있어야 합니다. 나머지 페이지는 공개됩니다. 메인 페이지의 일반적인 get-mapping을 포함하는 controllers클래스가 포함된 패키지를 만들어 보겠습니다 . IndexController클래스는 RegistrationController사용자 등록을 담당합니다. 사후 매핑은 양식에서 데이터를 가져와 사용자를 데이터베이스에 저장하고 로그인 페이지로 리디렉션합니다. PasswordEncoder나중에 설명하겠습니다. 비밀번호를 암호화하는 데 사용됩니다.
@Controller
public class RegistrationController
{
  @Autowired
  private UserRepo userRepo;

  @Autowired
  private PasswordEncoder passwordEncoder;

  @GetMapping("/registration")
  public String registration()
  {
     return "registration";
  }

  @PostMapping("/registration")
  public String addUser(String name, String username, String password)
  {
     User user = new User();
     user.setName(name);
     user.setUsername(username);
     user.setPassword(passwordEncoder.encode(password));
     user.setActive(true);
     user.setRoles(Collections.singleton(Role.USER));

     userRepo.save(user);

     return "redirect:/login";
  }
노트 목록 페이지를 담당하는 컨트롤러에는 현재 단순화된 기능이 포함되어 있지만 Spring Security 구현 이후에는 더욱 복잡해질 것입니다.
@Controller
public class NoteController
{
  @Autowired
  private NoteRepo noteRepo;

  @GetMapping("/notes")
  public String notes(Model model)
  {
     List<Note> notes = noteRepo.findAll();
     model.addAttribute("notes", notes);

     return "notes";
  }

  @PostMapping("/addnote")
  public String addNote(String title, String note)
  {
     Note newNote = new Note();
     newNote.setTitle(title);
     newNote.setNote(note);

     noteRepo.save(newNote);

     return "redirect:/notes";
  }
}
로그인 페이지에 대한 컨트롤러는 Spring Security에서 사용되므로 작성하지 않습니다. 대신 특별한 구성이 필요합니다. 평소처럼 다른 패키지를 만들어서 이름을 지정 config하고 거기에 클래스를 배치해 보겠습니다 MvcConfig. Spring Security 구성을 작성할 때 "/login"을 사용할 때 어떤 페이지를 참조하는지 알 수 있습니다.
@Configuration
public class MvcConfig implements WebMvcConfigurer
{
  public void addViewControllers(ViewControllerRegistry registry)
  {
     registry.addViewController("/login").setViewName("login");
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

페이지

저는 Mustache 템플릿 엔진을 사용하여 페이지를 만듭니다 . 다른 것을 구현할 수도 있지만 상관없습니다. 모든 페이지에 사용되는 메타정보에 대해 Meta.mustache 파일이 생성되었습니다. 또한 프로젝트 페이지를 더욱 예쁘게 보이게 해주는 Bootstrap도 포함되어 있습니다. 페이지는 "src/main/resources/templates" 디렉터리에 생성됩니다. 파일에는 확장명 콧수염이 있습니다. 기사에 html 코드를 직접 배치하면 기사가 너무 커지므로 여기에 프로젝트의 GitHub 저장소에 있는 템플릿 폴더에 대한 링크가 있습니다 .

클래식 로그인을 위한 Spring Security 구성

Spring Security는 애플리케이션과 해당 리소스를 무단 액세스로부터 보호하는 데 도움이 됩니다. SecurityConfig에서 상속된 클래스에서 간결한 작업 구성을 생성하고 WebSecurityConfigurerAdapter이를 패키지에 배치합니다 config. Spring Security 지원을 활성화하는 @EnableWebSecurity 주석과 이 클래스에 일부 구성이 포함되어 있음을 나타내는 @Configuration 주석으로 표시해 보겠습니다. 참고: 자동으로 구성된 pom.xml에는 Spring Boot 상위 구성 요소 2.1.4.RELEASE 버전이 포함되어 있어 보안이 설정된 방식으로 구현되지 않습니다. 프로젝트에서 충돌을 방지하려면 버전을 2.0.1.RELEASE로 변경하는 것이 좋습니다.

기본 구성 SecurityConfig

우리의 구성은 다음을 수행할 수 있습니다:
  1. 다음을 사용하여 비밀번호를 암호화합니다 BCryptPasswordEncoder.

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Bean
    PasswordEncoder passwordEncoder()
    {
      PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      return passwordEncoder;
    }
  2. 특별히 작성된 인증 공급자를 사용하여 로그인하십시오.

    @Autowired
    private AuthProvider authProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
    {
      auth.authenticationProvider(authProvider);
    }
  3. 익명 사용자가 홈 페이지, 등록 및 로그인 페이지에 액세스할 수 있도록 허용합니다. 다른 모든 요청은 로그인한 사용자가 수행해야 합니다. 앞서 설명한 "/login"을 로그인 페이지로 지정해 보겠습니다. 로그인에 성공하면 사용자는 메모 목록이 있는 페이지로 이동하고, 오류가 있으면 사용자는 로그인 페이지에 남아 있습니다. 성공적으로 종료되면 사용자는 기본 페이지로 이동됩니다.

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
      http
            .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login**", "/registration").permitAll()
            .anyRequest().authenticated()
            .and().formLogin().loginPage("/login")
            .defaultSuccessUrl("/notes").failureUrl("/login?error").permitAll()
            .and().logout().logoutSuccessUrl("/").permitAll();
    }

사용자 정의 사용자 로그인

직접 작성하면 AuthProvider사용자는 이메일뿐만 아니라 사용자 이름으로도 로그인할 수 있습니다.
@Component
public class AuthProvider implements AuthenticationProvider
{
  @Autowired
  private UserService userService;

  @Autowired
  private PasswordEncoder passwordEncoder;

  public Authentication authenticate(Authentication authentication) throws AuthenticationException
  {
     String username = authentication.getName();
     String password = (String) authentication.getCredentials();

     User user = (User) userService.loadUserByUsername(username);

     if(user != null && (user.getUsername().equals(username) || user.getName().equals(username)))
     {
        if(!passwordEncoder.matches(password, user.getPassword()))
        {
           throw new BadCredentialsException("Wrong password");
        }

        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();

        return new UsernamePasswordAuthenticationToken(user, password, authorities);
     }
     else
        throw new BadCredentialsException("Username not found");
  }

  public boolean supports(Class<?> arg)
  {
     return true;
  }
}
눈치채셨겠지만 UserService패키지에 있는 클래스는 사용자 로드를 담당합니다 services. username우리의 경우 내장된 구현처럼 필드뿐만 아니라 사용자 이름, Google 계정 이름 및 Google 계정 이메일로도 사용자를 검색합니다 . 마지막 두 가지 방법은 OAuth2를 통해 로그인을 구현할 때 유용합니다. 여기서 클래스는 축약된 버전으로 제공됩니다.
@Service
public class UserService implements UserDetailsService
{
  @Autowired
  private UserRepo userRepo;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
  {
     User userFindByUsername = userRepo.findByUsername(username);
     //Остальные поиски

     if(userFindByUsername != null)
     {
        return userFindByUsername;
     }
     //Остальные проверки
     return null;
  }
}
참고: 에 필요한 메소드를 작성하는 것을 잊지 마세요 UserRepo!

컨트롤러를 개선해보자

Spring Security를 ​​구성했습니다. 이제 Notes 컨트롤러에서 이 기능을 활용할 시간입니다. 이제 각 매핑은 사용자를 찾으려고 시도하는 추가 Principal 매개변수를 허용합니다. 왜 클래스를 직접 주입할 수 없나요 User? 그러면 소셜 네트워크를 통해 로그인을 작성할 때 사용자 유형의 불일치로 인해 충돌이 발생합니다. 우리는 필요한 유연성을 사전에 제공합니다. 이제 Notes 컨트롤러 코드는 다음과 같습니다.
@GetMapping("/notes")
public String notes(Principal principal, Model model)
{
  User user = (User) userService.loadUserByUsername(principal.getName());
  List<Note> notes = noteRepo.findByUserId(user.getId());
  model.addAttribute("notes", notes);
  model.addAttribute("user", user);

  return "notes";
}

@PostMapping("/addnote")
public String addNote(Principal principal, String title, String note)
{
  User user = (User) userService.loadUserByUsername(principal.getName());

  Note newNote = new Note();
  newNote.setTitle(title);
  newNote.setNote(note);
  newNote.setUserId(user.getId());

  noteRepo.save(newNote);

  return "redirect:/notes";
}
참고: 프로젝트에는 기본적으로 CSRF 보호가 활성화되어 있으므로 직접 비활성화하거나(http.csrf().disable()) 기사 작성자로서 csrf 토큰이 있는 숨겨진 필드를 추가하는 것을 잊지 마십시오. 모든 게시물 요청에.

시작하다

우리는 프로젝트를 시작하려고 합니다.
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 1
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 2
데이터베이스에 새로운 사용자가 나타난 것을 볼 수 있습니다. 비밀번호는 암호화되어 있습니다.
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 3
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 4
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 5
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 6
메모는 데이터베이스에 저장됩니다.
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 7
프로젝트가 성공적으로 시작되어 실행되고 있음을 알 수 있습니다. 완전한 행복을 위해서는 소셜 네트워크를 통해 로그인할 수 있는 능력만 있으면 됩니다. 자, 시작해 봅시다!

Spring Security의 예로 Google을 사용하여 OAuth2 설정

OAuth2를 구현할 때 저는 Spring의 공식 튜토리얼을 사용했습니다 . OAuth2를 지원하려면 pom.xml에 다음 라이브러리를 추가하세요.
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>
NET에서 Spring Security 구성을 수정해 보겠습니다 SecurityConfig. 먼저 @EnableOAuth2Client 주석을 추가해 보겠습니다. 소셜 네트워크를 통해 로그인하는 데 필요한 정보가 자동으로 표시됩니다.

필터 구성 및 application.properties

보안 구성에 사용할 OAuth2ClientContext를 삽입해 보겠습니다.
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
OAuth2ClientContext는 사용자의 소셜 로그인 요청을 검증하는 필터를 생성할 때 사용됩니다. @EnableOAuth2Client 주석 덕분에 필터를 사용할 수 있습니다. 우리가 해야 할 일은 기본 Spring Security 필터 이전에 올바른 순서로 호출하는 것뿐입니다 . 그래야만 OAuth2를 사용한 로그인 프로세스 중에 리디렉션을 포착할 수 있습니다. 이를 위해 FilterRegistrationBean필터 우선순위를 -100으로 설정하는 를 사용합니다.
@Bean
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter oAuth2ClientContextFilter)
{
  FilterRegistrationBean registration = new FilterRegistrationBean();
  registration.setFilter(oAuth2ClientContextFilter);
  registration.setOrder(-100);
  return registration;
}

private Filter ssoFilter()
{
  OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/google");
  OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oAuth2ClientContext);
  googleFilter.setRestTemplate(googleTemplate);
  CustomUserInfoTokenServices tokenServices = new CustomUserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId());
  tokenServices.setRestTemplate(googleTemplate);
  googleFilter.setTokenServices(tokenServices);
  tokenServices.setUserRepo(userRepo);
  tokenServices.setPasswordEncoder(passwordEncoder);
  return googleFilter;
}
또한 구성(HttpSecurity http) 함수에 새 필터를 추가해야 합니다.
http.addFilterBefore(ssoFilter(), UsernamePasswordAuthenticationFilter.class);
또한 필터는 클라이언트가 Google을 통해 등록했다는 사실도 알아야 합니다. @ConfigurationProperties 주석은 application.properties에서 찾을 구성 속성을 지정합니다.
@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google()
{
  return new AuthorizationCodeResourceDetails();
}
인증을 완료하려면 Google 사용자 정보 엔드포인트를 지정해야 합니다.
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource()
{
  return new ResourceServerProperties();
}
Google Cloud Platform 에 애플리케이션을 등록한 후 application.properties에 적절한 접두사가 있는 속성을 추가합니다.
google.client.clientId=yourClientId
google.client.clientSecret=yourClientSecret
google.client.accessTokenUri=https://www.googleapis.com/oauth2/v4/token
google.client.userAuthorizationUri=https://accounts.google.com/o/oauth2/v2/auth
google.client.clientAuthenticationScheme=form
google.client.scope=openid,email,profile
google.resource.userInfoUri=https://www.googleapis.com/oauth2/v3/userinfo
google.resource.preferTokenInfo=true

Google Cloud Platform 에 애플리케이션 등록의 주요 사항

경로: API 및 서비스 -> 자격 증명 OAuth 액세스 요청 창:
  • 애플리케이션 이름: Spring 로그인 양식 및 OAuth2 튜토리얼
  • 지원 이메일 주소: 귀하의 이메일
  • Google API 범위: 이메일, 프로필, openid
  • 승인된 도메인: me.org
  • 신청서 메인 페이지 링크: http://me.org:8080
  • 앱 개인정보 보호정책 링크: http://me.org:8080
  • 신청 이용약관 링크: http://me.org:8080
신임장:
  • 유형: 웹 애플리케이션
  • 제목: Spring 로그인 양식 및 OAuth2 튜토리얼
  • 허용되는 JavaScript 소스: http://me.org, http://me.org:8080
  • 허용되는 리디렉션 URI: http://me.org:8080/login, http://me.org:8080/login/google
참고: Google은 localhost:8080 주소로 작업하는 것을 원하지 않으므로 끝에 "127.0.0.1 me.org" 줄이나 C:\Windows\System32\drivers\etc\hosts 파일과 유사한 줄을 추가하세요. 가장 중요한 것은 도메인이 고전적인 형태라는 것입니다.

CustomUserInfoTokenServices

필터 기능 설명에서 Custom이라는 단어를 보셨나요? 수업 CustomUserInfoTokenServices. 예, 우리는 블랙잭과 사용자를 데이터베이스에 저장하는 기능을 갖춘 우리만의 클래스를 만들 것입니다! UserInfoTokenServicesIntelliJ IDEA에서 Ctrl-N 키보드 단축키를 사용하면 기본값이 어떻게 구현되는지 찾아 볼 수 있습니다 . 해당 코드를 새로 생성된 클래스에 복사해 보겠습니다 CustomUserInfoTokenServices. 대부분은 변경하지 않고 그대로 둘 수 있습니다. 함수의 논리를 변경하기 전에 UserRepo및 를 클래스의 비공개 필드로 추가해 보겠습니다 PasswordEncoder. 그들을 위한 세터를 만들어 보겠습니다. SecurityConfig 클래스에 @Autowired UserRepo userRepo를 추가해 보겠습니다. 필터 생성 방법에서 오류에 대한 포인터가 사라지는 모습을 보고 우리는 기뻐합니다. @Autowired를 CustomUserInfoTokenServices에 직접 적용할 수 없는 이유는 무엇입니까? 이 클래스는 자체적으로 Spring 주석으로 표시되지 않고 필터가 선언될 때 해당 생성자가 명시적으로 생성되므로 종속성을 선택하지 않기 때문입니다. 따라서 Spring의 DI 메커니즘은 이에 대해 알지 못합니다. 이 클래스의 어떤 항목에든 @Autowired 주석을 추가하면 사용 시 NullPointerException이 발생합니다. 그러나 명시적 설정자를 통해 모든 것이 매우 잘 작동합니다. 필요한 구성 요소를 구현한 후 관심 있는 주요 개체는 사용자에 대한 정보가 포함된 Map<String, Object>를 검색하는 loadAuthentication 함수가 됩니다. 이 프로젝트에서는 소셜 네트워크를 통해 로그인한 사용자를 데이터베이스에 저장하는 기능을 구현했습니다. Google 계정을 OAuth2 공급자로 사용하고 있으므로 지도에 Google에 일반적인 "sub" 필드가 포함되어 있는지 확인합니다. 존재하는 경우 사용자에 대한 정보가 올바르게 수신되었음을 의미합니다. 새로운 사용자를 생성하고 이를 데이터베이스에 저장합니다.
@Override
public OAuth2Authentication loadAuthentication(String accessToken)
     throws AuthenticationException, InvalidTokenException
{
  Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);

  if(map.containsKey("sub"))
  {
     String googleName = (String) map.get("name");
     String googleUsername = (String) map.get("email");

     User user = userRepo.findByGoogleUsername(googleUsername);

     if(user == null)
     {
        user = new User();
        user.setActive(true);
        user.setRoles(Collections.singleton(Role.USER));
     }

     user.setName(googleName);
     user.setUsername(googleUsername);
     user.setGoogleName(googleName);
     user.setGoogleUsername(googleUsername);
     user.setPassword(passwordEncoder.encode("oauth2user"));

     userRepo.save(user);
  }

  if (map.containsKey("error"))
  {
     this.logger.debug("userinfo returned error: " + map.get("error"));
     throw new InvalidTokenException(accessToken);
  }
  return extractAuthentication(map);
}
여러 공급자를 사용하는 경우 하나의 CustomUserInfoTokenServices에 서로 다른 옵션을 지정하고 필터 선언 메서드에 유사한 서비스의 서로 다른 클래스를 등록할 수 있습니다. 이제 User와 OAuth2Authentication이 모두 주체 역할을 할 수 있습니다. Google 데이터를 통해 사용자를 로드하는 것을 UserService에서 미리 고려했기 때문에 애플리케이션은 두 유형의 사용자 모두에게 작동합니다. OAuth2를 사용하여 로그인한 사용자를 노트 페이지로 리디렉션하도록 프로젝트의 기본 페이지 컨트롤러를 수정합니다.
@GetMapping("/")
public String index(Principal principal)
{
  if(principal != null)
  {
     return "redirect:/notes";
  }
  return "index";
}

프로젝트의 최종 출시

사소한 외관 변경과 종료 버튼 추가 후 프로젝트의 최종 출시를 수행합니다.
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 8
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 9
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 10
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 11
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 12
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 13
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 14
Notes 서비스의 예를 사용하여 Spring Security에 이메일 및 OAuth2를 통한 일반 로그인을 도입해 보겠습니다. - 15
사용자는 일반 양식과 Google 계정을 통해 성공적으로 로그인했습니다. 이것이 우리가 원했던 것입니다! 이 기사를 통해 웹 애플리케이션 생성, Spring Security로 보안 유지, 다양한 로그인 방법 결합에 대한 몇 가지 요점을 정리할 수 있었으면 좋겠습니다. 전체 프로젝트 코드를 사용하면 다음을 수행할 수 있습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION