구글 로그인 연동 및 스프링 시큐리티 설정
본 포스팅은 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 책을 보고 작성하였음
1. 도메인 User 클래스 생성
User
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@NoArgsConstructor
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
@Column
private String picture;
@Enumerated(EnumType.STRING) ⓐ
@Column(nullable = false)
private Role role;
@Builder
public User(String name, String email, String picture, Role role) {
this.name = name;
this.email = email;
this.picture = picture;
this.role = role;
}
public User update(String name, String picture) {
this.name = name;
this.picture = picture;
return this;
}
public String getRoleKey() {
return this.role.getKey();
}
}
- ⓐ @Enumerated(EnumType.STRING)
- JPA로 데이터베이스로 저장할 때 Enum 값을 어떤 형대로 저장할지를 결정함
- 기본적으로 int로 된 숫자가 저장됨
- 숫자로 저장되면 데이터베이스로 확인할 때 그 값이 무슨 코드를 의미하는지 알 수가 없음, 그래서 문자열(EnumType.STRING)로 저장될 수 있도록 선언함
Role
- 사용자의 권한을 관리할 Enum 클래스
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum Role {
GUEST("ROLE_GUEST", "손님"),
USER("ROLE_USER", "일반 사용자");
private final String key;
private final String title;
}
- 스프링 시큐리티에서는 권한 코드에 항상 ROLE_이 앞에 있어야만 함
UserRepository
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
2. 스프링 시큐리티 설정
2.1 build.gradle 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
- spring-boot-starter-oauth2-client
- 소셜 로그인 등 클라이언트 입장에서 소셜 기능 구현 시 필요한 의존성임
- spring-security-oauth2-client와 spring-security-oauth2-jose를 기본으로 관리해줌
2.2 config.auth 패키지 생성
- 시큐리티 관련 클래스
2.2.1 SecurithConfig
import com.study.aws.studyspringbootaws.domain.user.Role;
import lombok.RequiredArgsConstructor;
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;
@RequiredArgsConstructor
@EnableWebSecurity ⓐ
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.headers().frameOptions().disable() ⓑ
.and()
.authorizeRequests() ⓒ
.antMatchers("/", "/css/**", "/images/**", "/js/**", "/h2-console/**")
.permitAll()
.antMatchers("/api/v1/**") ⓓ
.hasRole(Role.USER.name())
.anyRequest() ⓔ
.authenticated()
.and()
.logout()
.logoutSuccessUrl("/") ⓕ
.and()
.oauth2Login() ⓖ
.userInfoEndpoint() ⓗ
.userService(customOAuth2UserService) ⓘ
;
}
}
- ⓐ @EnableWebSecurity
- Spring Security 설정들을 활성화시켜 줌
- ⓑ csrf().disable().headers().frameOptions().disable()
- h2-console 화면을 사용하기 위해 해당 옵션들을 disable 처리함
- ⓒ authorizeRequests()
- URL별 권한 관리를 설정하는 옵션의 시작점
- authorizeRequests가 선언되어야만 antMatchers 옵션을 사용할 수 있음
- ⓓ antMatchers("/api/v1/**")
- 권한 관리 대상을 지정하는 옵션임
- URL, HTTP 메소드별로 관리가 가능함
- permitAll() 옵션을 통해 전체 권한을 줌
- hasRole() 옵션을 통해 해당 권한이 있는 사용자에게 접근 가능하도록 함
- ⓔ anyRequest()
- 설정된 값들 이외의 나머지 URL들을 나타냄
- authenticated()를 추가하여 나머지 URL들을 모두 인증된 사용자들에게 허용하게 함
- 인증된 사용자 즉, 로그인한 사용자들을 이야기함
- ⓕ logout().logoutSuccessUrl("/")
- 로그아웃 기능에 대한 여러 설정 진입점임
- 로그아웃 성공시 "/" 주소로 이동한다는 의미
- ⓖ oauth2Login()
- OAuth 2 로그인 기능에 대한 여려 설정의 진입점임
- ⓗ userInfoEndpoint()
- OAuth 2 로그인 성공 이후 사용자 정보를 가져올 때의 설정들을 담당함
- ⓘ userService(특정 UserService)
- 소셜 로그인 성공 시 후속 조치를 진행할 UserService 인터페이스의 구현체를 등록함
- 리소스 서버(즉, 소셜 서비스들)에서 사용자 정보를 가져온 상태에서 추가로 진행하고자 하는 기능을 명시 할 수 있음
2.2.2 CustomOAuth2UserService
- 구글 로그인 이후 가져온 사용자의 정보들을 기반으로 가입 및 정보 수정, 세션 저장 등의 기능을 지원함
@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
String registrationId = userRequest.getClientRegistration().getRegistrationId(); ⓐ
String userNameAttributeName =
userRequest.getClientRegistration()
.getProviderDetails()
.getUserInfoEndpoint()
.getUserNameAttributeName(); ⓑ
OAuthAttributes attributes = OAuthAttributes.of(registrationId,
userNameAttributeName,
oAuth2User.getAttributes()); ⓒ
User user = saveOrUpdate(attributes);
httpSession.setAttribute("user", new SessionUser(user)); ⓓ
return new DefaultOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(),
attributes.getNameAttributeKey()
);
}
private User saveOrUpdate(OAuthAttributes attributes) {
User user = userRepository.findByEmail(attributes.getEmail())
.map(entity -> entity.update(attributes.getName(),
attributes.getPicture()))
.orElse(attributes.toEntity());
return userRepository.save(user);
}
}
- ⓐ registrationId
- 현재 로그인 진행 중인 서비스를 구분하는 코드
- 현재 상기 코드에서는 구글만 사용하므로 불필요한 값이지만, 기타 다른 로그인 연동 시 다른 서비스인지를 구분하기위해 사용함(ex. 네이버 로그인인지, 구글인지, 카카오인지 확인하기 위한 ID 값)
- ⓑ userNameAttributeName
- OAuth2 로그인 진행 시 키가 되는 필드값을 이야기 함 (Primary Key와 같은 의미라 보면 됨)
- 구글의 경우 기본적으로 코드를 지원하지만, 네이버 카카오 등은 기본으로 지원하지 않음! 구글의 기본 코드는 "sub"임
- 이후 네이버 로그인과 구글 로그인을 동시 지원할 때 사용할 예정
- ⓒ OAuthAttributes
- OAuth2UserService를 통해 가져온 OAuth2User의 attribute를 담을 클래스임
- 이후 네이버 등 다른 소셜 로그인도 이 클래스를 사용함
- ⓓ SessionUser
- 세션에 사용자 정보를 저장하기 위한 DTO 클래스임
2.2.3 OAuthAttributes
- DTO 패키지를 만들어 클래스 생성
@Getter
public class OAuthAttributes {
private Map<String, Object> attributes;
private String nameAttributeKey;
private String name;
private String email;
private String picture;
@Builder
public OAuthAttributes(Map<String, Object> attributes,
String nameAttributeKey, String name,
String email, String picture) {
this.attributes = attributes;
this.nameAttributeKey = nameAttributeKey;
this.name = name;
this.email = email;
this.picture = picture;
}
public static OAuthAttributes of(String registrationId,
String userNameAttributeName,
Map<String, Object> attributes) { ⓐ
return ofGoogle(userNameAttributeName, attributes);
}
private static OAuthAttributes ofGoogle(String userNameAttributeName,
Map<String, Object> attributes) {
return OAuthAttributes.builder()
.name((String) attributes.get("name"))
.email((String) attributes.get("email"))
.picture((String) attributes.get("picture"))
.attributes(attributes)
.nameAttributeKey(userNameAttributeName)
.build()
;
}
public User toEntity() { ⓑ
return User.builder()
.name(name)
.email(email)
.picture(picture)
.role(Role.GUEST)
.build();
}
}
- ⓐ of()
- OAuth2User에서 반환하는 사용자 정보는 Map이기 때문에 값 하나하나를 변환해야함 함
- ⓑ toEntity()
- User 엔티티를 생성함
- OAuthAttributes에서 엔티티를 생성하는 시점은 처음 가입할 때임
- 가입할 때의 기본 권한을 GUEST로 주기 위해서 role 빌더값에는 Role.GUEST 값을 주었음
- OAuthAttributes 클래스 생성이 끝났으면 같은 패키지에 SessionUser 클래스를 생성함
2.2.4 SessionUser
@Getter
public class SessionUser implements Serializable {
private String name;
private String email;
private String picture;
public SessionUser(User user) {
this.name = user.getName();
this.email = user.getEmail();
this.picture = user.getPicture();
}
}
2.2.5 왜 User 클래스를 사용하지 않고 SessionUser를 따로 만들었나?
- 세션에 저장을 위해 클래스의 직렬화가 필요함
- User 클래스는 엔티티이기 때문에 직렬화 하기 힘듬
- 엔티티 클래스는 언제 다른 엔티티와 관계가 형성될지 모름
- ex) @OneToMany or @ManytoMany 등 자식 엔티티를 갖고 있다면 직렬화 대상에 해당 엔티티도 포함되므로 성능이슈, 부수효과가 발생할 가능성이 높음
3. 로그인 테스트
3.1 화면에 로그인 기능 추가
3.1.1 index.mustache
<h1>스프링 부트로 시작하는 웹 서비스</h1>
<div class="col-md-12">
<div class="row">
<div class="col-md-6">
<a href="/posts/save" role="button" class="btn btn-primary">글 등록</a>
{{#userName}} ⓐ
Logged in as : <span id="user">{{userName}}</span>
<a href="/logout" class="btn btn-info active" role="button">Logout</a> ⓑ
{{/userName}}
{{^userName}} ⓒ
<a href="/oauth2/authorization/google" class="btn btn-info active" role="button">Google Login</a> ⓓ
{{/userName}}
</div>
</div>
</div>
- ⓐ {{#userName}}
- 머스테치는 true/false 여부만 판단함, if문 없음
- 항상 최종값을 넘겨줘야 함
- ⓑ a href="/logout"
- 스프링 시큐리티에서 기본적으로 제공하는 로그아웃 URL
- 즉, 개발자가 별도로 저 URL에 해당하는 컨트롤러를 만들 필요가 없음
- SecurityConfig 클래스에서 URL 변경 가능
- ⓒ {{^userName}}
- 머스테치에서는 해당 값이 존재하지 않을 경우에는 ^를 사용함
- ⓓ a href="/oauth2/authorization/google"
- 스프링 시큐리티에서 기본적으로 제공하는 구글 로그인 URL
3.1.2 indexController
private final HttpSession httpSession;
@GetMapping("/")
public String index(Model model) {
model.addAttribute("posts", postsService.findAllDesc());
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if (user != null) {
model.addAttribute("userName", user.getName());
}
return "index";
}
3.2 프로젝트 실행하여 테스트
- 로그인버튼화면
- 구글 로그인
- 로그인 정보 DB 확인
- 게시글 등록 (GUEST 상태일때)
- 권한 변경 후 등록
Author And Source
이 문제에 관하여(구글 로그인 연동 및 스프링 시큐리티 설정), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@young_209/구글-로그인-연동-및-스프링-시큐리티-설정
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@NoArgsConstructor
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
@Column
private String picture;
@Enumerated(EnumType.STRING) ⓐ
@Column(nullable = false)
private Role role;
@Builder
public User(String name, String email, String picture, Role role) {
this.name = name;
this.email = email;
this.picture = picture;
this.role = role;
}
public User update(String name, String picture) {
this.name = name;
this.picture = picture;
return this;
}
public String getRoleKey() {
return this.role.getKey();
}
}
- JPA로 데이터베이스로 저장할 때 Enum 값을 어떤 형대로 저장할지를 결정함
- 기본적으로 int로 된 숫자가 저장됨
- 숫자로 저장되면 데이터베이스로 확인할 때 그 값이 무슨 코드를 의미하는지 알 수가 없음, 그래서 문자열(EnumType.STRING)로 저장될 수 있도록 선언함
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum Role {
GUEST("ROLE_GUEST", "손님"),
USER("ROLE_USER", "일반 사용자");
private final String key;
private final String title;
}
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
2.1 build.gradle 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
- spring-boot-starter-oauth2-client
- 소셜 로그인 등 클라이언트 입장에서 소셜 기능 구현 시 필요한 의존성임
- spring-security-oauth2-client와 spring-security-oauth2-jose를 기본으로 관리해줌
2.2 config.auth 패키지 생성
- 시큐리티 관련 클래스
2.2.1 SecurithConfig
import com.study.aws.studyspringbootaws.domain.user.Role;
import lombok.RequiredArgsConstructor;
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;
@RequiredArgsConstructor
@EnableWebSecurity ⓐ
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.headers().frameOptions().disable() ⓑ
.and()
.authorizeRequests() ⓒ
.antMatchers("/", "/css/**", "/images/**", "/js/**", "/h2-console/**")
.permitAll()
.antMatchers("/api/v1/**") ⓓ
.hasRole(Role.USER.name())
.anyRequest() ⓔ
.authenticated()
.and()
.logout()
.logoutSuccessUrl("/") ⓕ
.and()
.oauth2Login() ⓖ
.userInfoEndpoint() ⓗ
.userService(customOAuth2UserService) ⓘ
;
}
}
- ⓐ @EnableWebSecurity
- Spring Security 설정들을 활성화시켜 줌
- ⓑ csrf().disable().headers().frameOptions().disable()
- h2-console 화면을 사용하기 위해 해당 옵션들을 disable 처리함
- ⓒ authorizeRequests()
- URL별 권한 관리를 설정하는 옵션의 시작점
- authorizeRequests가 선언되어야만 antMatchers 옵션을 사용할 수 있음
- ⓓ antMatchers("/api/v1/**")
- 권한 관리 대상을 지정하는 옵션임
- URL, HTTP 메소드별로 관리가 가능함
- permitAll() 옵션을 통해 전체 권한을 줌
- hasRole() 옵션을 통해 해당 권한이 있는 사용자에게 접근 가능하도록 함
- ⓔ anyRequest()
- 설정된 값들 이외의 나머지 URL들을 나타냄
- authenticated()를 추가하여 나머지 URL들을 모두 인증된 사용자들에게 허용하게 함
- 인증된 사용자 즉, 로그인한 사용자들을 이야기함
- ⓕ logout().logoutSuccessUrl("/")
- 로그아웃 기능에 대한 여러 설정 진입점임
- 로그아웃 성공시 "/" 주소로 이동한다는 의미
- ⓖ oauth2Login()
- OAuth 2 로그인 기능에 대한 여려 설정의 진입점임
- ⓗ userInfoEndpoint()
- OAuth 2 로그인 성공 이후 사용자 정보를 가져올 때의 설정들을 담당함
- ⓘ userService(특정 UserService)
- 소셜 로그인 성공 시 후속 조치를 진행할 UserService 인터페이스의 구현체를 등록함
- 리소스 서버(즉, 소셜 서비스들)에서 사용자 정보를 가져온 상태에서 추가로 진행하고자 하는 기능을 명시 할 수 있음
2.2.2 CustomOAuth2UserService
- 구글 로그인 이후 가져온 사용자의 정보들을 기반으로 가입 및 정보 수정, 세션 저장 등의 기능을 지원함
@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
String registrationId = userRequest.getClientRegistration().getRegistrationId(); ⓐ
String userNameAttributeName =
userRequest.getClientRegistration()
.getProviderDetails()
.getUserInfoEndpoint()
.getUserNameAttributeName(); ⓑ
OAuthAttributes attributes = OAuthAttributes.of(registrationId,
userNameAttributeName,
oAuth2User.getAttributes()); ⓒ
User user = saveOrUpdate(attributes);
httpSession.setAttribute("user", new SessionUser(user)); ⓓ
return new DefaultOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(),
attributes.getNameAttributeKey()
);
}
private User saveOrUpdate(OAuthAttributes attributes) {
User user = userRepository.findByEmail(attributes.getEmail())
.map(entity -> entity.update(attributes.getName(),
attributes.getPicture()))
.orElse(attributes.toEntity());
return userRepository.save(user);
}
}
- ⓐ registrationId
- 현재 로그인 진행 중인 서비스를 구분하는 코드
- 현재 상기 코드에서는 구글만 사용하므로 불필요한 값이지만, 기타 다른 로그인 연동 시 다른 서비스인지를 구분하기위해 사용함(ex. 네이버 로그인인지, 구글인지, 카카오인지 확인하기 위한 ID 값)
- ⓑ userNameAttributeName
- OAuth2 로그인 진행 시 키가 되는 필드값을 이야기 함 (Primary Key와 같은 의미라 보면 됨)
- 구글의 경우 기본적으로 코드를 지원하지만, 네이버 카카오 등은 기본으로 지원하지 않음! 구글의 기본 코드는 "sub"임
- 이후 네이버 로그인과 구글 로그인을 동시 지원할 때 사용할 예정
- ⓒ OAuthAttributes
- OAuth2UserService를 통해 가져온 OAuth2User의 attribute를 담을 클래스임
- 이후 네이버 등 다른 소셜 로그인도 이 클래스를 사용함
- ⓓ SessionUser
- 세션에 사용자 정보를 저장하기 위한 DTO 클래스임
2.2.3 OAuthAttributes
- DTO 패키지를 만들어 클래스 생성
@Getter
public class OAuthAttributes {
private Map<String, Object> attributes;
private String nameAttributeKey;
private String name;
private String email;
private String picture;
@Builder
public OAuthAttributes(Map<String, Object> attributes,
String nameAttributeKey, String name,
String email, String picture) {
this.attributes = attributes;
this.nameAttributeKey = nameAttributeKey;
this.name = name;
this.email = email;
this.picture = picture;
}
public static OAuthAttributes of(String registrationId,
String userNameAttributeName,
Map<String, Object> attributes) { ⓐ
return ofGoogle(userNameAttributeName, attributes);
}
private static OAuthAttributes ofGoogle(String userNameAttributeName,
Map<String, Object> attributes) {
return OAuthAttributes.builder()
.name((String) attributes.get("name"))
.email((String) attributes.get("email"))
.picture((String) attributes.get("picture"))
.attributes(attributes)
.nameAttributeKey(userNameAttributeName)
.build()
;
}
public User toEntity() { ⓑ
return User.builder()
.name(name)
.email(email)
.picture(picture)
.role(Role.GUEST)
.build();
}
}
- ⓐ of()
- OAuth2User에서 반환하는 사용자 정보는 Map이기 때문에 값 하나하나를 변환해야함 함
- ⓑ toEntity()
- User 엔티티를 생성함
- OAuthAttributes에서 엔티티를 생성하는 시점은 처음 가입할 때임
- 가입할 때의 기본 권한을 GUEST로 주기 위해서 role 빌더값에는 Role.GUEST 값을 주었음
- OAuthAttributes 클래스 생성이 끝났으면 같은 패키지에 SessionUser 클래스를 생성함
2.2.4 SessionUser
@Getter
public class SessionUser implements Serializable {
private String name;
private String email;
private String picture;
public SessionUser(User user) {
this.name = user.getName();
this.email = user.getEmail();
this.picture = user.getPicture();
}
}
2.2.5 왜 User 클래스를 사용하지 않고 SessionUser를 따로 만들었나?
- 세션에 저장을 위해 클래스의 직렬화가 필요함
- User 클래스는 엔티티이기 때문에 직렬화 하기 힘듬
- 엔티티 클래스는 언제 다른 엔티티와 관계가 형성될지 모름
- ex) @OneToMany or @ManytoMany 등 자식 엔티티를 갖고 있다면 직렬화 대상에 해당 엔티티도 포함되므로 성능이슈, 부수효과가 발생할 가능성이 높음
- User 클래스는 엔티티이기 때문에 직렬화 하기 힘듬
3. 로그인 테스트
3.1 화면에 로그인 기능 추가
3.1.1 index.mustache
<h1>스프링 부트로 시작하는 웹 서비스</h1>
<div class="col-md-12">
<div class="row">
<div class="col-md-6">
<a href="/posts/save" role="button" class="btn btn-primary">글 등록</a>
{{#userName}} ⓐ
Logged in as : <span id="user">{{userName}}</span>
<a href="/logout" class="btn btn-info active" role="button">Logout</a> ⓑ
{{/userName}}
{{^userName}} ⓒ
<a href="/oauth2/authorization/google" class="btn btn-info active" role="button">Google Login</a> ⓓ
{{/userName}}
</div>
</div>
</div>
- ⓐ {{#userName}}
- 머스테치는 true/false 여부만 판단함, if문 없음
- 항상 최종값을 넘겨줘야 함
- ⓑ a href="/logout"
- 스프링 시큐리티에서 기본적으로 제공하는 로그아웃 URL
- 즉, 개발자가 별도로 저 URL에 해당하는 컨트롤러를 만들 필요가 없음
- SecurityConfig 클래스에서 URL 변경 가능
- ⓒ {{^userName}}
- 머스테치에서는 해당 값이 존재하지 않을 경우에는 ^를 사용함
- ⓓ a href="/oauth2/authorization/google"
- 스프링 시큐리티에서 기본적으로 제공하는 구글 로그인 URL
3.1.2 indexController
private final HttpSession httpSession;
@GetMapping("/")
public String index(Model model) {
model.addAttribute("posts", postsService.findAllDesc());
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if (user != null) {
model.addAttribute("userName", user.getName());
}
return "index";
}
3.2 프로젝트 실행하여 테스트
- 로그인버튼화면
- 구글 로그인
- 로그인 정보 DB 확인
- 게시글 등록 (GUEST 상태일때)
- 권한 변경 후 등록
Author And Source
이 문제에 관하여(구글 로그인 연동 및 스프링 시큐리티 설정), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@young_209/구글-로그인-연동-및-스프링-시큐리티-설정
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
<h1>스프링 부트로 시작하는 웹 서비스</h1>
<div class="col-md-12">
<div class="row">
<div class="col-md-6">
<a href="/posts/save" role="button" class="btn btn-primary">글 등록</a>
{{#userName}} ⓐ
Logged in as : <span id="user">{{userName}}</span>
<a href="/logout" class="btn btn-info active" role="button">Logout</a> ⓑ
{{/userName}}
{{^userName}} ⓒ
<a href="/oauth2/authorization/google" class="btn btn-info active" role="button">Google Login</a> ⓓ
{{/userName}}
</div>
</div>
</div>
- 머스테치는 true/false 여부만 판단함, if문 없음
- 항상 최종값을 넘겨줘야 함
- 스프링 시큐리티에서 기본적으로 제공하는 로그아웃 URL
- 즉, 개발자가 별도로 저 URL에 해당하는 컨트롤러를 만들 필요가 없음
- SecurityConfig 클래스에서 URL 변경 가능
- 머스테치에서는 해당 값이 존재하지 않을 경우에는 ^를 사용함
- 스프링 시큐리티에서 기본적으로 제공하는 구글 로그인 URL
private final HttpSession httpSession;
@GetMapping("/")
public String index(Model model) {
model.addAttribute("posts", postsService.findAllDesc());
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if (user != null) {
model.addAttribute("userName", user.getName());
}
return "index";
}
Author And Source
이 문제에 관하여(구글 로그인 연동 및 스프링 시큐리티 설정), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@young_209/구글-로그인-연동-및-스프링-시큐리티-설정저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)