1. 기본 세팅
application.yml
server: servlet: encoding: charset: utf-8 force: true port: 8080 spring: mustache: servlet: expose-request-attributes: true expose-session-attributes: true datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:test;MODE=MySQL username: sa password: h2: console: enabled: true jpa: hibernate: ddl-auto: create # none, update show-sql: true properties: hibernate: format_sql: true defer-datasource-initialization: true #테이블이 create 되고 난 이후에 sql init 해라 sql: init: data-locations: classpath:db/data.sql
2. 화면 구현하기
join-form.mustache
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>회원가입 페이지</h1> <hr> <form action="/join" method="post"> <input type="text" placeholder="username" value="ssar" name="username"> <br> <input type="password" placeholder="password" value="1234" name="password"> <br> <input type="email" placeholder="email" value="ssar@nate.com" name="email"> <br> <button type="submit">회원가입</button> </form> </body> </html>
login-form.mustache
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>로그인 페이지</h1> <hr> <form action="/login" method="post"> <input type="text" placeholder="username" value="ssar" name="username"> <br> <input type="password" placeholder="password" value="1234" name="password"> <br> <button type="submit">로그인</button> </form> <a href="#">카카오 로그인</a> </body> </html>
main.mustache
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>메인(인증된) 페이지 : ssar</h1> <hr> <div> 상품이름 : 바나나 <br> 가격 : 1000 <br> 재고 : 20 <br> <hr> </div> <div> 상품이름 : 바나나 <br> 가격 : 1000 <br> 재고 : 20 <br> <hr> </div> </body> </html>
3. 기본 기능 구현하기
User
package org.example.loginapp.user; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @NoArgsConstructor @Getter @Table(name = "user_tb") @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(unique = true) private String username; private String password; private String email; private String provider ; // facebook , kakao, apple, naver ... oauth 인증을 위한 필드 private String address; @Builder public User(Integer id, String username, String password, String email, String provider,String address) { this.id = id; this.username = username; this.password = password; this.email = email; this.provider = provider; this.address = address; } }
UserController
package org.example.loginapp.user; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @RequiredArgsConstructor @Controller public class UserController { private final UserService userService; private final HttpSession session; @GetMapping("/oauth/callback") public String callback(String code) { System.out.println("콜백 완료 : "+ code); User sessionUser = userService.카카오로그인(); session.setAttribute("sessionUser",sessionUser); return "redirect:/shop"; } @GetMapping("/join-form") public String joinForm() { return "join-form"; } @GetMapping("/login-form") public String loginForm(){ return "login-form"; } @PostMapping("/join") public String join(String username, String password, String email){ userService.회원가입(username,password,email); return "redirect:/login-form"; } @PostMapping("/login") public String login(String username, String password){ User sessionUser = userService.로그인(username,password); session.setAttribute("sessionUser",sessionUser); return "redirect:/shop"; } }
UserRepository
package org.example.loginapp.user; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; public interface UserRepository extends JpaRepository<User, Integer> { //select * from user_tb where username = ? User findByUsername(@Param("username") String username); }
UserService
package org.example.loginapp.user; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; @Transactional public void 회원가입(String username, String password,String email){ User user = User.builder() .username(username) .password(password) .email(email) .build(); userRepository.save(user); } public User 로그인(String username, String password){ User user = userRepository.findByUsername(username); if(user == null){ throw new RuntimeException("아이디가 없습니다."); }else { if(user.getPassword().equals(password)){ return user; }else { throw new RuntimeException("비밀번호가 틀렸습니다."); } } } }
Shop
package org.example.loginapp.shop; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @NoArgsConstructor @Getter @Table(name = "shop_tb") @Entity public class Shop { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id ; private String name; // 상품명 private String price; // 가격 private Integer qty ; // 재고 @Builder public Shop(Integer id, String name, String price, Integer qty) { this.id = id; this.name = name; this.price = price; this.qty = qty; } }
ShopController
package org.example.loginapp.shop; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.example.loginapp.user.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import java.util.List; @RequiredArgsConstructor @Controller public class ShopController { private final ShopService shopService; private final HttpSession session ; @GetMapping("/shop") public String main(HttpServletRequest request){ User sessionUser = (User) session.getAttribute("sessionUser"); if(sessionUser == null){ throw new RuntimeException("인증된 사용자가 아닙니다"); } List<Shop> shopList = shopService.상품목록(); request.setAttribute("shopList",shopList); return "main"; } }
ShopRepository
package org.example.loginapp.shop; import org.springframework.data.jpa.repository.JpaRepository; public interface ShopRepository extends JpaRepository<Shop, Integer> { }
ShopService
package org.example.loginapp.shop; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.List; @RequiredArgsConstructor @Service public class ShopService { private final ShopRepository shopRepository; public List<Shop> 상품목록() { List<Shop> shopList = shopRepository.findAll(); return shopList ; } }
main.mustache
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>메인(인증된) 페이지 : {{sessionUser.username}}</h1> <hr> {{#shopList}} <div> 상품이름 : {{name}} <br> 가격 : {{price}} <br> 재고 : {{qty}} <br> <hr> </div> {{/shopList}} </body> </html>
data.sql
insert into shop_tb(name,price,qty) values ('바나나',1000,10); insert into shop_tb(name,price,qty) values ('딸기',2000,10); insert into shop_tb(name,price,qty) values ('참외',3000,10);
4. 카카오 OAuth 페이지 둘러보기
카카오 개발자 센터
카카오 개발자 센터 - 문서 - 카카오 로그인 을 선택한다.
로그인 방식을 확인할 수 있다.
앱 설정에서 설정해야 할 항목을 볼 수 있다.
5. 필수 설정
5.1 플랫폼 등록
내 애플리케이션 - 애플리케이션 추가하기를 눌러 새로운 애플리케이션을 추가해준다.
추가한 애플리케이션 - 플랫폼을 들어가 어떤 플랫폼인지를 등록한다. 지금은 웹서버기 때문에 web을 선택한다.
5.2 카카오 로그인 활성화
플랫폼 등록 후 하단 등록하러 가기 or 카카오 로그인을 선택 후 활성화 설정을 On 으로 설정한다.
5.3 Redirect URI 등록
카카오 로그인 하단의 Redirect URI 버튼을 선택한다.
Redirect URI는 카카오 로그인 인증 과정에서 사용자가 카카오 로그인 페이지에서 인증을 완료한 후, 인증 결과를 받을 애플리케이션의 URL을 의미한다. 사용자 인증이 성공하거나 실패한 후 카카오가 사용자를 다시 리디렉션할 URL 주소이다.
UserController
package org.example.loginapp.user; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @RequiredArgsConstructor @Controller public class UserController { private final UserService userService; private final HttpSession session; @GetMapping("/oauth/callback") public String callback(String code) { System.out.println("콜백 완료 : " + code); User sessionUser = userService.카카오로그인(code); session.setAttribute("sessionUser", sessionUser); return "redirect:/shop"; } @GetMapping("/join-form") public String joinForm() { return "join-form"; } @GetMapping("/login-form") public String loginForm() { return "login-form"; } @PostMapping("/join") public String join(String username, String password, String email) { userService.회원가입(username, password, email); return "redirect:/login-form"; } @PostMapping("/login") public String login(String username, String password) { User sessionUser = userService.로그인(username, password); session.setAttribute("sessionUser", sessionUser); return "redirect:/shop"; } }
UserController 에 Redirect URI 를 만들어준다.
5.4 동의 항목 설정
동의 항목은 사용자가 애플리케이션에 로그인할 때 제공할 개인 정보 및 권한에 대해 동의하는 항목들이다. 이는 사용자가 어떤 정보에 접근을 허용할지, 애플리케이션이 어떤 권한을 가질지를 정의한다. 카카오 로그인 동의 항목에는 필수 항목과 선택 항목이 포함되며, 사용자가 로그인할 때 이를 확인하고 동의해야 한다.
개인정보 동의항목 심사 신청은 사업자 정보가 있어야 등록할 수 있다. 지금은 테스트용이기 때문에 닉네임만 설정하도록한다.
실제 서비스에선 동의 항목 중 이메일이 가장 중요한 데이터이다. 그래서 이메일을 꼭 받아야하지만 현재는 이메일을 받을 수 없기 때문에 닉네임을 이메일 형태로 만들 예정이다.
Share article