[spring boot] 게시판 스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현 - 03
브라우저에서 로그인 테스트
index.mustache 추가 작성
{{>layout/header}}
<h1>스프링부트로 시작하는 웹 서비스 Ver.2</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>
{{#loginuserName}}
Logged in as: <span id="user">{{loginuserName}}</span>
<a href="/logout" class="btn btn-info active" role="button">Logout</a>
{{/loginuserName}}
{{^loginuserName}}
<a href="/oauth2/authorization/google" class="btn btn-success active" role="button">Google Login</a>
{{/loginuserName}}
</div>
</div>
<br>
<!-- 목록 출력 영역 -->
<table class="table table-horizontal table-bordered">
<thead class="thead-strong">
<tr>
<th>게시글번호</th>
<th>제목</th>
<th>작성자</th>
<th>최종수정일</th>
</tr>
</thead>
<tbody id="tbody">
{{#posts}}
<tr>
<td>{{id}}</td>
<td><a href="/posts/update/{{id}}">{{title}}</a></td>
<td>{{author}}</td>
<td>{{modifiedDate}}</td>
</tr>
{{/posts}}
</tbody>
</table>
</div>
{{>layout/footer}}
-
{{#userName}}, {{/userName}}
머스테치에서는 if문을 제공하지 않습니다.
true/false 여부만 판단 합니다.
userName이 있다면 userName을 노출 시키는 구문
-
a href="/logout"
스프링 시큐리티에서 기본적으로 제공하는 로그아웃 URL
별도로 로그아웃 api를 컨트롤러에 작성하지 않아도됨
앞서 작성한 SecurityConfig클래스에서 URL을 변경할 수 있음
-
{{^userName}}, {{/userName}}
머스테치에서 userName값이 존재하지 않을때 로그인 버튼을 노출시키는 구문
-
a href="/oauth2/authorization/google"
스프리 시큐리티에서 기본적으로 제공하는 로그인 URL
로그아웃과 마찬가지로 api를 생성하지 않아도됨
IndexController 추가 작성
package com.momenting.book.springboot.web;
import com.momenting.book.springboot.config.auth.dto.SessionUser;
import com.momenting.book.springboot.service.posts.PostsService;
import com.momenting.book.springboot.web.dto.PostsResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.servlet.http.HttpSession;
@RequiredArgsConstructor
@Controller
public class IndexController {
private final PostsService postsService;
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";
}
@GetMapping("/posts/save")
public String postsSave() {
return "posts-save";
}
@GetMapping("/posts/update/{id}")
public String postsUpdate(@PathVariable Long id, Model model) {
PostsResponseDto dto = postsService.findById(id);
model.addAttribute("post", dto);
return "posts-update";
}
}
-
이번 포스팅에서 추가 작성된 구문
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("loginuserName", user.getName());
}
return "index";
}
구글 로그인 테스트
{{>layout/header}}
<h1>스프링부트로 시작하는 웹 서비스 Ver.2</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>
{{#loginuserName}}
Logged in as: <span id="user">{{loginuserName}}</span>
<a href="/logout" class="btn btn-info active" role="button">Logout</a>
{{/loginuserName}}
{{^loginuserName}}
<a href="/oauth2/authorization/google" class="btn btn-success active" role="button">Google Login</a>
{{/loginuserName}}
</div>
</div>
<br>
<!-- 목록 출력 영역 -->
<table class="table table-horizontal table-bordered">
<thead class="thead-strong">
<tr>
<th>게시글번호</th>
<th>제목</th>
<th>작성자</th>
<th>최종수정일</th>
</tr>
</thead>
<tbody id="tbody">
{{#posts}}
<tr>
<td>{{id}}</td>
<td><a href="/posts/update/{{id}}">{{title}}</a></td>
<td>{{author}}</td>
<td>{{modifiedDate}}</td>
</tr>
{{/posts}}
</tbody>
</table>
</div>
{{>layout/footer}}
{{#userName}}, {{/userName}}
머스테치에서는 if문을 제공하지 않습니다.
true/false 여부만 판단 합니다.
userName이 있다면 userName을 노출 시키는 구문
a href="/logout"
스프링 시큐리티에서 기본적으로 제공하는 로그아웃 URL
별도로 로그아웃 api를 컨트롤러에 작성하지 않아도됨
앞서 작성한 SecurityConfig클래스에서 URL을 변경할 수 있음
{{^userName}}, {{/userName}}
머스테치에서 userName값이 존재하지 않을때 로그인 버튼을 노출시키는 구문
a href="/oauth2/authorization/google"
스프리 시큐리티에서 기본적으로 제공하는 로그인 URL
로그아웃과 마찬가지로 api를 생성하지 않아도됨
package com.momenting.book.springboot.web;
import com.momenting.book.springboot.config.auth.dto.SessionUser;
import com.momenting.book.springboot.service.posts.PostsService;
import com.momenting.book.springboot.web.dto.PostsResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.servlet.http.HttpSession;
@RequiredArgsConstructor
@Controller
public class IndexController {
private final PostsService postsService;
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";
}
@GetMapping("/posts/save")
public String postsSave() {
return "posts-save";
}
@GetMapping("/posts/update/{id}")
public String postsUpdate(@PathVariable Long id, Model model) {
PostsResponseDto dto = postsService.findById(id);
model.addAttribute("post", dto);
return "posts-update";
}
}
이번 포스팅에서 추가 작성된 구문
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("loginuserName", user.getName());
}
return "index";
}
Google Login 버튼을 클릭하면
와 같이 구글 로그인 동의 화면으로 이동합니다. 로그인할 계정을 선택하면 로그인이 진행됩니다.
구글프로필에서의 사용자 이름이 노출 됩니다. 하지만 h2데이터베이스에서 확인해 보면
저의 구글 계정정보가 잘 저장된것을 확인할 수 있습니다.
권한 변경하기
권한을 변경하기전에 로그인 후 게시글을 등록하게되면 권한이 GUEST기 때문에 글 등록이 안될것 입니다.
그래서 권한을 USER로 변경해준 후 게시글을 등록한다면 글 등록이 달 될겁니다.
어노테이션 기반으로 개선하기
@LoginUser 어노테이션 생성
-
config.auth 패키지에 생성해 줍니다
-
작성
package com.momenting.book.springboot.config.auth;
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 LoginUser {
}
LoginUserArgumentResolver 생성
-
config.auth 패키지에 생성해 줍니다
-
작성
package com.momenting.book.springboot.config.auth;
import com.momenting.book.springboot.config.auth.dto.SessionUser;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpSession;
@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
private final HttpSession httpSession;
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean isLoginUserAnnotation = parameter.getParameterAnnotation(LoginUser.class) != null;
boolean isUserClass = SessionUser.class.equals(parameter.getParameterType());
return isLoginUserAnnotation && isUserClass;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return httpSession.getAttribute("user");
}
}
WebConfig 생성
-
config 패키지에 생성해 줍니다
-
작성
package com.momenting.book.springboot.config;
import com.momenting.book.springboot.config.auth.LoginUserArgumentResolver;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final LoginUserArgumentResolver loginUserArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(loginUserArgumentResolver);
}
}
IndexController 변경
package com.momenting.book.springboot.web;
import com.momenting.book.springboot.config.auth.LoginUser;
import com.momenting.book.springboot.config.auth.dto.SessionUser;
import com.momenting.book.springboot.service.posts.PostsService;
import com.momenting.book.springboot.web.dto.PostsResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.servlet.http.HttpSession;
@RequiredArgsConstructor
@Controller
public class IndexController {
private final PostsService postsService;
@GetMapping("/")
public String index(Model model, @LoginUser SessionUser user) {
model.addAttribute("posts", postsService.findAllDesc());
if (user != null) {
model.addAttribute("loginuserName", user.getName());
System.out.println("얍얍4" +user.getName());
}
return "index";
}
@GetMapping("/posts/save")
public String postsSave() {
return "posts-save";
}
@GetMapping("/posts/update/{id}")
public String postsUpdate(@PathVariable Long id, Model model) {
PostsResponseDto dto = postsService.findById(id);
model.addAttribute("post", dto);
return "posts-update";
}
}
세션 저장소로 데이터베이스 사용하기
의존성 추가
- build.gradle에 compile('org.springframework.session:spring-session-jdbc') 추가해 줍니다.
application.properties 추가
- spring.session.store-type=jdbc라는 구문을 추가로 작성해 줍니다.
Author And Source
이 문제에 관하여([spring boot] 게시판 스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현 - 03), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dudgns1086/spring-boot-게시판-스프링-시큐리티와-OAuth2.0으로-로그인-기능-구현-03저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)