๋ก๊ทธ์ธ ์ฒ๋ฆฌ - ์ฟ ํค, ์ธ์
by rlaehddnd0422๋ก๊ทธ์ธ ์๊ตฌ์ฌํญ
ํ ํ๋ฉด - ๋ก๊ทธ์ธ ์
- ํ์ ๊ฐ์
- ๋ก๊ทธ์ธ
ํ ํ๋ฉด - ๋ก๊ทธ์ธ ํ
- ๋ณธ์ธ ์ด๋ฆ ( ๋ก๊ทธ์ธ : ~ )
- ์ํ ๊ด๋ฆฌ
- ๋ก๊ทธ ์์
๋ณด์ ์๊ตฌ์ฌํญ
- ๋ก๊ทธ์ธ ์ฌ์ฉ์๋ง ์ํ์ ์ ๊ทผํ๊ณ , ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ๋ก๊ทธ์ธ ํ์ง ์์ ์ฌ์ฉ์๊ฐ ์ํ ๊ด๋ฆฌ์ ์ ๊ทผํ๋ฉด ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก ์ด๋
ํจํค์ง ๊ตฌ์กฐ ์ค๊ณ
ํจํค์ง ๊ตฌ์กฐ - domain, web
๋๋ฉ์ธ์ ์์คํ ์ด ๊ตฌํํด์ผ ํ๋ ํต์ฌ ๋น์ฆ๋์ค ์ ๋ฌด ์์ญ์ ๋งํฉ๋๋ค.
๋์ค์ web์ ๋ค๋ฅธ ๊ธฐ์ ๋ก ๋ฐ๊พธ์ด๋ ๋๋ฉ์ธ์ ๊ทธ๋๋ก ์ ์งํ ์ ์์ด์ผ ํฉ๋๋ค.
web์ domain์ ์์กดํ์ง๋ง domain์ web์ ์์กดํ์ง ์๋๋ก ์ค๊ณํด์ผ ํจ.
๋ฐ๋ผ์ ํจํค์ง ๊ตฌ์กฐ๋ฅผ ์ ์ค๊ณํ๋ ๊ฒ์ด ์ค์.
๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ
ํ ํ๋ฉด
HomeController์ ์ถ๊ฐ
@GetMapping("/")
public String home() {
return "home";
}
home.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link th:href="@{/css/bootstrap.min.css}"
href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>ํ ํ๋ฉด</h2> </div>
<div class="row">
<div class="col">
<button class="w-100 btn btn-secondary btn-lg" type="button"
th:onclick="|location.href='@{/members/add}'|">
ํ์ ๊ฐ์
</button>
</div>
<div class="col">
<button class="w-100 btn btn-dark btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/login}'|" type="button">
๋ก๊ทธ์ธ
</button>
</div>
</div>
<hr class="my-4">
</div> <!-- /container -->
</body>
</html>
ํ์๊ฐ์ ๋ฒํผ ํด๋ฆญ ์ -> URI "localhost:8080/members/add" ๋ก ์ด๋
๋ก๊ทธ์ธ ๋ฒํผ ํด๋ฆญ ์ -> URI "localhost:8080/login"๋ก ์ด๋
Domain - Member
@Data
public class Member {
private Long id;
@NotEmpty
private String loginId;
@NotEmpty
private String name;
@NotEmpty
private String password;
public Member(){}
public Member(String loginId, String name, String password) {
this.loginId = loginId;
this.name = name;
this.password = password;
}
}
ํ์ ๊ฐ์ , ๋ก๊ทธ์ธ์ ์ฌ์ฉ๋๋ ๊ฐ์ฒด์ ๋๋ค.
Domain - MemberRepository
@Slf4j
@Repository
public class MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
public Member save(Member member)
{
member.setId(++sequence);
log.info("save : member = {}",member);
store.put(member.getId(),member);
return member;
}
public Member findById(Long id)
{
return store.get(id);
}
public Optional<Member> findByLoginId(String loginId)
{
// List<Member> members = findAll();
// for (Member m : members) {
// if(m.getLoginId() == loginId)
// {
// return Optional.of(m);
// }
// }
// return Optional.empty();
return findAll().stream()
.filter(m -> m.getLoginId().equals(loginId))
.findFirst();
}
public List<Member> findAll()
{
return new ArrayList<>(store.values());
}
public void clearStore()
{
store.clear();
}
}
MemberRepository for member ์ ์ฅ.
(๋๊ฐ ์ธํฐํ์ด์ค ๋ ๋ฒจ๋ก ์ ์ธํ๊ณ ๊ตฌํ์ฒด๋ฅผ ๋ณ๋๋ก ๊ตฌํํด์ ์ฐ๋ ๊ฒ ์ ์์ด๊ธด ํฉ๋๋ค - ๊ฐ์๋ผ์ฐ๊ธฐ ์ํด)
ํ์ ๊ฐ์ ํ๋ฉด
@Controller
@RequiredArgsConstructor
@RequestMapping("/members")
public class MemberController {
private final MemberRepository memberRepository;
@GetMapping("/add")
public String addForm(@ModelAttribute("member") Member member)
{
return "members/addMemberForm";
}
- ํ์ ๊ฐ์ ๋ฒํผ ์ -> /members/add๋ก ์ด๋ -> addMemberForm ๋ทฐํ ํ๋ฆฟ์ ํธ์ถํฉ๋๋ค.
- addMemberForm์์ th:object=${member}"๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด @ModelAttribute Member member๋ฅผ argument๋ก ์ค์ ํ์ต๋๋ค.
- Model์ argument๋ก ์ค์ ํ๊ณ model.addAttribute("member",member)๋ก ๋ชจ๋ธ์ ๊ฐ์ฒด๋ฅผ ๋ด๊ณ addMemberForm ๋ทฐํ ํ๋ฆฟ ํธ์ถํ๋ ๋ฐฉ์๊ณผ ๋์ผํฉ๋๋ค.
@PostMapping("/add")
public String save(@Validated @ModelAttribute("member") Member member, BindingResult bindingResult)
{
if(bindingResult.hasErrors())
{
return "members/addMemberForm";
}
memberRepository.save(member);
return "redirect:/";
}
- addMemberForm์์ HTML From ์ ๋ ฅ์ ํตํด ํ์ ์ ๋ณด๋ฅผ ์ ๋ ฅ๋ฐ๊ณ ํ์ฌ URL์ Post ์์ฒญํฉ๋๋ค. ( th:action์ ๋ณ๋์ URL์ ์ง์ ํ์ง ์์ผ๋ฉด ํ์ฌ URL์ Post ์์ฒญ)
- HTML Form POST ์ ์ก์ ํตํด ๊ฒ์ฆ์ ๊ฑฐ์ณ @ModelAttribute Member member์ ๋ด๊ณ ๊ฒ์ฆ ์ค๋ฅ ๋ฐ์ ์ bindingResult์ ์ค๋ฅ๋ฅผ ๋ด์ต๋๋ค.
- bindingResult์ ์ค๋ฅ๊ฐ ์์ ๊ฒฝ์ฐ -> ๋ฑ๋ก ํผ ์์ฒญ
- bindingResult์ ์ค๋ฅ๊ฐ ์์ ๊ฒฝ์ฐ -> ์ ์ฅ์์ ํ์๋ด๊ณ home์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ
๋ก๊ทธ์ธ ํ๋ฉด
@GetMapping("/login")
public String loginForm(@ModelAttribute("loginForm") LoginForm loginForm)
{
return "login/loginForm";
}
- ํ ํ๋ฉด์์ ๋ก๊ทธ์ธ ๋ฒํผ ํด๋ฆญ ์ -> "localhost:8080/login" URL ์์ฒญ -> loginForm ๋ทฐ ํ ํ๋ฆฟ ํธ์ถ
- loginForm์์ th:object="${loginForm}" ์ฌ์ฉ์ ํ๊ธฐ ์ํด ๋ชจ๋ธ์ ๋ด์์ฃผ์์ต๋๋ค.
@PostMapping("/login")
public String login(@Valid @ModelAttribute LoginForm loginForm, BindingResult bindingResult)
{
if(bindingResult.hasErrors())
{
return "login/loginForm";
}
Member loginMember = loginService.login(loginForm.getLoginId(), loginForm.getPassword());
// ์คํจ
if(loginMember == null)
{
bindingResult.reject("loginFail","์์ด๋ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
return "login/loginForm";
}
// ์ฑ๊ณต
return "redirect:/";
}
- loginForm ๋ทฐ ํ ํ๋ฆฟ์ HTML Form์ผ๋ก๋ถํฐ Post๋ ๋ฐ์ดํฐ๋ค์ @ModelAttribute loginForm์ ๋ด์ ๊ฒ์ฆ๊ณผ์ ์ ๊ฑฐ์น ํ ์ค๋ฅ๊ฐ ์์ผ๋ฉด bindingResult์ ๋ด์ต๋๋ค. ( th:action์ ๋ณ๋์ URL์ ์ง์ ํ์ง ์์ผ๋ฉด ํ์ฌ URL์ Post ์์ฒญ)
- ์ด ๋ ๋ง์ฐฌ๊ฐ์ง๋ก bindingResult์ ์ค๋ฅ๊ฐ ๋ด๊ฒจ์์ผ๋ฉด loginForm ๋ทฐ ํ
ํ๋ฆฟ์ ๋ค์ ํธ์ถํฉ๋๋ค.
- ์ฐธ๊ณ ๋ก loginForm์์๋ ๊ธ๋ก๋ฒ์ค๋ฅ, ํ๋์ค๋ฅ๊ฐ ์์์ ํด๋น ์ค๋ฅ์ ๋ํ ์ค๋ฅ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋๋ก ์ค์ ํ์ต๋๋ค.
Member loginMember = loginService.login(loginForm.getLoginId(), loginForm.getPassword());
- loginService์์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ํตํด ์์ด๋๋ฅผ ์ฐพ๊ณ ํจ์ค์๋๊น์ง ์ผ์นํ๋ฉด ํด๋น ํ์์ ๋ฆฌํดํ๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ null ๋ฆฌํด
- ๋ก๊ทธ์ธ ์คํจ ์ ๊ธ๋ก๋ฒ ์ค๋ฅ์ ๋ด์์ ๋ค์ loginForm ๋ทฐ ํ ํ๋ฆฟ์ ํธ์ถํฉ๋๋ค.
- ๋ก๊ทธ์ธ ์ฑ๊ณต ์ home์ผ๋ก redirectํฉ๋๋ค.
์ฌ๊ธฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋ก๊ทธ์ธ์ ์ฑ๊ณตํ๋ฉด ๊ธฐ๋ํ๋ฉด ์ฒ๋ผ ๋ก๊ทธ์ธ ์ ๋ณด๊ฐ ๋์จ ์ํ๋ก home์ผ๋ก ์ด๋ํด์ผ ํ๋๋ฐ ์๊ตฌ์ฌํญ์ ๋ง์กฑํ์ง ๋ชปํ๊ณ ์์ต๋๋ค.
๋ก๊ทธ์ธ์ ์ฑ๊ณตํ ์ฌ์ฉ์๋ ํ ํ๋ฉด์ ์ ๊ทผํ ๊ฒฝ์ฐ ๋ก๊ทธ์ธ์ ์ํ๋ฅผ ์ ์งํ๋ฉด์ ๊ณ ๊ฐ์ ์ด๋ฆ์ ๋ณด์ฌ์ฃผ๊ฒ ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น์?
ํด๋ผ์ด์ธํธ๊ฐ ๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ๋ด์ ์ฑ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด์ฉํ๊ธฐ ์ํด์๋ ์ฟ ํค๋ ์ธ์ ์ด ํ์ํฉ๋๋ค.
์ง๊ธ๊น์ง๋ ๊ฐ๋จํ๊ฒ ํผ๊ณผ ์ปจํธ๋กค๋ฌ๋ฅผ ์ด์ฉํด ๋ก๊ทธ์ธ ์ปจํธ๋กค๋ฌ๋ฅผ ๊ตฌํ๋ง ํด๋ณด์์ต๋๋ค.
์ด์ ์ฟ ํค์ ์ธ์ ์ ์ฌ์ฉํด์ ๋ก๊ทธ์ธ์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ฒ๋ฆฌํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฟ ํค๋ฅผ ์ฌ์ฉํด ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
์ฟ ํค๋ฅผ ์ฌ์ฉํ๋ฉด ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค.
HTTP๋ ๋ฌด์ํ ํ๋กํ ์ฝ์ ๋๋ค / ํด๋ผ์ด์ธํธ - ์๋ฒ๊ฐ ์์ฒญ๊ณผ ์๋ต์ ์ฃผ๊ณ ๋ฐ์ผ๋ฉด ์ฐ๊ฒฐ์ด ๋์ด์ง.
ํด๋ผ์ด์ธํธ๊ฐ ๋ค์ ์์ฒญํ๋ฉด ์๋ฒ๋ ์ด์ ์์ฒญ์ ๊ธฐ์ตํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์, ๋ชจ๋ ์์ฒญ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํฌํจํด์ผ ํฉ๋๋ค.
์ด ๋ ์ฟ ํค์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ด์์ ์๋ฒ์ ๋ด์ ์ ์กํ๋ค๋ฉด ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์๊ฒ ์ฃ ?
https://rlaehddnd0422.tistory.com/45#article-5--http---%EC%BF%A0%ED%82%A4-%ED%97%A4%EB%8D%94
โ๏ธ์ฐธ๊ณ
์ฟ ํค์๋ ๋ง๋ฃ๋ ์ง๋ฅผ ์ ๋ ฅํ๋ฉด ํด๋น ๋ ์ง๊น์ง ์ ์ง๋๋ ( ์น๋ธ๋ผ์ฐ์ ๋ฅผ ๋ซ์๋ ์ฌ๋ผ์ง์ง ์์) ์์ ์ฟ ํค์,
๋ธ๋ผ์ฐ์ ์ข ๋ฃํ๊ธฐ ์ ๊น์ง๋ง ์ ์ง๋๋ ์ธ์ ์ฟ ํค๊ฐ ์์ต๋๋ค.
๋ก๊ทธ์ธ ์ฑ๊ณต - ์ฟ ํค ์์ฑ
๋ก๊ทธ์ธ ์ฑ๊ณต ์์ ์ธ์ ์ฟ ํค๋ฅผ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.
// ์คํจ
if(loginMember == null)
{
bindingResult.reject("loginFail","์์ด๋ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
return "login/loginForm";
}
// ์ฟ ํค set
Cookie idCookie = new Cookie("memberId",String.valueOf(loginMember.getId()));
response.addCookie(idCookie);
// ์ฑ๊ณต
return "redirect:/";
๋ก๊ทธ์ธ์ ์ฑ๊ณตํ๋ฉด ์ฟ ํค๋ฅผ ์์ฑํ๊ณ response ์๋ธ๋ฆฟ ๊ฐ์ฒด์ ๋ด์์ ๋ณด๋ด์ฃผ์ด์ผ๊ฒ ์ฃ .
์ฟ ํค ์ด๋ฆ์ "memberId"๋ก ์ค์ ํ๊ณ , ๊ฐ์ ํ์์ id๋ฅผ ๋ด์๋์์ต๋๋ค. ์น ๋ธ๋ผ์ฐ์ ๋ ์ข ๋ฃ ์ ๊น์ง ํ์์ id๋ฅผ ์๋ฒ์ ๊ณ์ ๋ณด๋ด์ค ๊ฒ์ ๋๋ค.
๋ก๊ทธ์ธ ํ ํ์ธํด ๋ณด๋ฉด
HTTP ์๋ต ํค๋์ ์ฟ ํค๊ฐ ์ถ๊ฐ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
์ด์ ์๊ตฌ์ฌํญ์ ๋ง์ถ์ด ๋ก๊ทธ์ธ์ ์ฑ๊ณตํ๋ฉด ๋ก๊ทธ์ธ ์ฑ๊ณต ํ ํ๋ฉด์ผ๋ก ์ด๋ํ๋๋ก ์ค์ ํด๋ณด๊ฒ ์ต๋๋ค.
// @GetMapping("/")
// public String home() {
// return "home";
// }
@GetMapping("/")
public String homeLogin(@CookieValue(name="memberId", required=false) Long memberId, Model model)
{
if(memberId==null)
{
return "home";
}
Member loginMember = memberRepository.findById(memberId);
if(loginMember == null)
{
return "home";
}
model.addAttribute("member",loginMember);
return "loginHome";
}
@CookieValue๋ฅผ ์ฌ์ฉํ๋ฉด ํธ๋ฆฌํ๊ฒ ์ฟ ํค๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
์ด์ ํ ํ๋ฉด์์๋ ๋ฌด์กฐ๊ฑด์ ์ผ๋ก home ๋ทฐํ ํ๋ฆฟ์ผ๋ก ์ด๋ํ๋ ๊ฒ ์๋๋ผ ์ฟ ํค ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก
- ๋ก๊ทธ์ธ ์ฟ ํค(memberId) ๊ฐ ์์ผ๋ฉด memberId ๊ธฐ๋ฐ์ ๋ก๊ทธ์ธ ์ฌ์ฉ์ ์ ์ฉ ํ ํ๋ฉด์ธ loginForm์ผ๋ก ๋ณด๋ด๊ณ
- ๋ก๊ทธ์ธ ์ฟ ํค๊ฐ ์์ผ๋ฉด home์ผ๋ก ๋ณด๋ด๋๋ก ์ค์ ํ์ต๋๋ค.
- loginForm์์ ๋ก๊ทธ์ธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๊ธฐ ๋ชจ๋ธ์ member๋ฅผ ๋ด์ ํธ์ถ
<h4 class="mb-3" th:text="|๋ก๊ทธ์ธ: ${member.name}|">๋ก๊ทธ์ธ ์ฌ์ฉ์ ์ด๋ฆ</h4>
...
<div class="col">
<button class="w-100 btn btn-secondary btn-lg" type="button"
th:onclick="|location.href='@{/items}'|">
์ํ ๊ด๋ฆฌ
</button>
</div>
<div class="col">
<form th:action="@{/logout}" method="post">
<button class="w-100 btn btn-dark btn-lg" type="submit">
๋ก๊ทธ์์
</button>
</form>
</div>
- loginForm์์ ๋ก๊ทธ์ธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ถ๋ ฅ
- ์ํ๊ด๋ฆฌ ๋ฒํผ ํด๋ฆญ ์ -> /items๋ก ์ด๋
- ๋ก๊ทธ์์ ๋ฒํผ ํด๋ฆญ ์ -> /logout์ผ๋ก Post ์์ฒญํฉ๋๋ค.
๋ก๊ทธ์์์ ํ๋ฉด ๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ์ญ์ ํ ์ํ๋ก homeํ๋ฉด์ผ๋ก ์ด๋ํด์ผ ํฉ๋๋ค. ๊ทธ๋ ๊ฒ ํ๊ธฐ ์ํด์๋ ์ฟ ํค๋ฅผ ์ญ์ ํด์ผ ํฉ๋๋ค.
๋ก๊ทธ์์ - ์ฟ ํค ์ญ์
@PostMapping("/logout")
public String logout(HttpServletResponse response)
{
expireCookie(response,"memberId");
return "redirect:/";
}
private void expireCookie(HttpServletResponse response, String cookieName) {
Cookie cookie = new Cookie(cookieName, null);
cookie.setMaxAge(0);
response.addCookie(cookie);
}
response์๋ ์ฟ ํค๋ฅผ ์ญ์ ํ๋ ๋ฉ์๋๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ด๋ ๊ฒ ๊ฐ์ ์ ์ผ๋ก ์ฟ ํค์ ์ ํจ์๊ฐ์ 0์ผ๋ก ์ค์ ํด์ ์ฟ ํค๋ฅผ ์ญ์ ํ ์ ์์ต๋๋ค.
public void deleteCookie(HttpServletResponse res){
Cookie cookie = new Cookie("์ญ์ ํ๊ณ ์ถ์ ์ฟ ํค ID", null); // ์ญ์ ํ ์ฟ ํค์ ๋ํ ๊ฐ์ null๋ก ์ง์
cookie.setMaxAge(0); // ์ ํจ์๊ฐ์ 0์ผ๋ก ์ค์ ํด์ ๋ฐ๋ก ๋ง๋ฃ์ํจ๋ค.
res.addCookie(cookie); // ์๋ต์ ์ถ๊ฐํด์ ์์ด์ง๋๋ก ํจ
}
https://blog.naver.com/PostView.nhn?blogId=adamdoha&logNo=222081530284
์ฟ ํค ๋ณด์ ๋ฌธ์
์ฟ ํค๋ ์์๋ก ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ณด์ ์ ์ข์ ๋ฐฉ๋ฒ์ด ์๋๋๋ค.
ํด๋ผ์ด์ธํธ๊ฐ ์ฟ ํค๋ฅผ ๊ฐ์ ๋ก ๋ณ๊ฒฝํ๋ฉด ๋ค๋ฅธ ์ฌ์ฉ์๋ก ์๋ฒ์ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋์
- ์ฟ ํค์ ์ค์ํ ๊ฐ์ ๋ ธ์ถํ์ง ์๊ณ , ์ฌ์ฉ์ ๋ณ๋ก ์์ธก ๋ถ๊ฐ๋ฅํ ์์์ ํ ํฐ์ ๋ ธ์ถํ๊ณ , ์๋ฒ์์ ํ ํฐ๊ณผ ์ฌ์ฉ์ id๋ฅผ ๋งคํํด์ ์ธ์ํ๋ ๋ฐฉ๋ฒ + ์๊ฐ์ด ์ง๋๋ฉด ์ฌ์ฉํ ์ ์๋๋ก ์๋ฒ์์ ํด๋น ํ ํฐ์ ๋ง๋ฃ์๊ฐ์ ์งง๊ฒ ์ ์ง.
๋ก๊ทธ์ธ ์ฒ๋ฆฌ - ์ธ์
์ธ์ ๋์ ๋ฐฉ์
์ค์ํ ์ ๋ณด๋ ๋ชจ๋ ์๋ฒ์ ์ ์ฅํ๊ณ , ํด๋ผ์ด์ธํธ์ ์๋ฒ๋ ์ถ์ ๋ถ๊ฐ๋ฅํ ์์์ ์๋ณ์๋ฅผ ํตํด ์ฐ๊ฒฐํ๋ ๋ฐฉ์์ ์ธ์ ์ด๋ผ๊ณ ํฉ๋๋ค.
๋ก๊ทธ์ธ ์
1. ID, PASSWORD๋ฅผ ํตํด ์๋ฒ์ ๋ก๊ทธ์ธ ์์ฒญ
2. ์๋ฒ์์๋ ํด๋ผ์ด์ธํธ์ ID, PASSWORD๋ฅผ ํตํด ๋ฆฌํฌ์งํ ๋ฆฌ์์ ํ์ ์กฐํ
3. ์ผ์นํ๋ ๋ฉค๋ฒ ๋ฆฌํด
4. UUID ๊ธฐ๋ฐ ํ ํฐ์ ํ๋ ์์ฑํฉ๋๋ค. ์ธ์ ์ Token - ๋ฉค๋ฒ ์ ์ฅ
5. response์ Token์ ์ฟ ํค์ ๋ด์์ ํด๋ผ์ด์ธํธ์ ์ ์กํฉ๋๋ค.
๋ก๊ทธ์ธ ์ดํ
6. ๋ฐ์ ์ฟ ํค์ ํ ํฐ์ ๊ธฐ๋ฐ์ผ๋ก ํ ๋๋ ํ ๋ฆฌ GET ์์ฒญ
+ ์๋ฒ๋ ์ธ์ ์ ์ฅ์์ ํ ํฐ ๊ธฐ๋ฐ์ผ๋ก ๋ฉค๋ฒ๋ฅผ ๋ฆฌํดํด์ ํด๋ผ์ด์ธํธ์ ์๋ต
์ด๋ ๊ฒ ์ธ์ ์ ์ฌ์ฉํด ์ค์ํ ์ ๋ณด๋ฅผ ์๋ฒ์์ ๊ด๋ฆฌํ๊ณ ์์ธก ๋ถ๊ฐ๋ฅํ ํ ํฐ ๊ฐ์ ์ฟ ํค๋ก ์ค์ ํด ํด๋ผ์ด์ธํธ๋ ์ฟ ํค๊ฐ์ ์์ธกํด์ ์ค์ ํด์ ์๋ฒ์ ์์ฒญํ ์ ์๋๋ก ์ค์ ํด ๋ณด์์ ๊ฐํํ ์ ์์ต๋๋ค.
์ธ์ ์ ์ง์ ๊ฐ๋ฐํด๋ณธ ํ, ์คํ๋ง์ด ์ง์ํ๋ ์ธ์ ์ ์ฌ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์ธ์ ์ง์ ๊ฐ๋ฐ
SessionManager์ ์ธ์ ์์ฑ, ์กฐํ, ์ญ์ ๊ตฌํ
public static final String SESSION_COOKIE_NAME = "mySessionId";
// key - uuid , value - ๊ฐ์ฒด
private Map<String, Object> sessionStore = new ConcurrentHashMap<>();
์ธ์ ์์ฑ
private Map<String, Object> sessionStore = new ConcurrentHashMap<>();
// ์ธ์ ์์ฑ
public void createSession(Object value, HttpServletResponse response)
{
String sessionId = UUID.randomUUID().toString();
sessionStore.put(sessionId,value);
Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
response.addCookie(mySessionCookie);
}
- ์ธ์ ์ ์ง์ ๊ฐ๋ฐํ๊ธฐ ์ํด Map์ ์ฌ์ฉํ์ต๋๋ค.
- ์์ฑํ ๋์๋ UUID๋ฅผ ํ๋ ๋ง๋ค์ด ํ ํฐ์ผ๋ก ์ค์ ํด์ ์ธ์ ์ ์ฅ์์ ๋ฃ์ด์ฃผ์์ต๋๋ค.
- ์์ฑํ ํ ํฐ์ ์ฟ ํค๋ก ์ค์ ํด์ response์ ์ถ๊ฐํด์ฃผ์์ต๋๋ค.
์ธ์ ์กฐํ
// ์ธ์
์กฐํ
public Object getSession(HttpServletRequest request)
{
Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
if(sessionCookie==null)
{
return null;
}
return sessionStore.get(sessionCookie.getValue());
}
private Cookie findCookie(HttpServletRequest request, String cookieName)
{
if(request.getCookies()==null)
{
return null;
}
return Arrays.stream(request.getCookies())
.filter(c -> c.getName().equals(cookieName))
.findAny()
.orElse(null);
}
- request์์ ์ฟ ํค๊ฐ ์์ผ๋ฉด null ๋ฆฌํด
- request์ cookieName์ ์ฟ ๊ธฐ๊ฐ ์์ผ๋ฉด ์ธ์ ์ ์ฅ์์์ ํ ํฐ์ ๋งค์นญ๋ ํ์ ๋ฆฌํด, ์์ผ๋ฉด null ๋ฆฌํด
์ธ์ ๋ง๋ฃ
// ์ธ์
๋ง๋ฃ
public void expire(HttpServletRequest request)
{
Cookie sessionCookie = findCookie(request,SESSION_COOKIE_NAME);
if(sessionCookie!=null)
{
sessionStore.remove(sessionCookie.getValue());
}
}
- request์์ ์ธ์ ์ ์กฐํํด ํด๋น ์ธ์ ์์ผ๋ฉด ์ธ์ ์ ์ฅ๋งต์์ ์ญ์
์ปจํธ๋กค๋ฌ์ ์ ์ฉ
@PostMapping("/login")
public String loginV2(@Valid @ModelAttribute LoginForm loginForm, BindingResult bindingResult,
HttpServletResponse response)
{
if(bindingResult.hasErrors())
{
return "login/loginForm";
}
Member loginMember = loginService.login(loginForm.getLoginId(),loginForm.getPassword());
// ์คํจ
if(loginMember == null)
{
bindingResult.reject("loginFail","์์ด๋ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
return "login/loginForm";
}
// ์ธ์
๊ด๋ฆฌ์๋ฅผ ํตํด ์ธ์
์์ฑ -> ํ์๋ฐ์ดํฐ ๋ณด๊ด
sessionManager.createSession(loginMember,response);
// ์ฑ๊ณต
return "redirect:/";
}
- private final SessionManager sessionManager; - ์์กด๊ด๊ณ ์ฃผ์
- sessionManager.createSession(loginMember, response);
- ๋ก๊ทธ์ธ ์ฑ๊ณต์ ์ธ์ ์ ๋ฑ๋กํฉ๋๋ค. ์ธ์ ์ loginMember ๋ฅผ ์ ์ฅํด๋๊ณ , ์ฟ ํค(ํ ํฐ, loginMember)๋ ๋ฐํ.
HomeController ๋ณ๊ฒฝ - ๋ก๊ทธ์ธ ํ ํ๋ฉด
@GetMapping("/")
public String homeLoginV2(HttpServletRequest request, Model model)
{
// ์ธ์
๊ด๋ฆฌ์์ ์ ์ฅ๋ ํ์ ์ ๋ณด ์กฐํ
Member member = (Member) sessionManager.getSession(request);
if(member == null)
{
return "home";
}
model.addAttribute("member",member);
return "loginHome";
}
- ํ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํด์ Get ์์ฒญ์ ์ธ์ ๊ด๋ฆฌ์์ ์ ์ฅ๋ ํ์ ์ ๋ณด๋ฅผ ์กฐํํด ๋ฆฌํด๋ฐ์ Object๋ฅผ ํ์ ์ ๋ฉค๋ฒ๋ก ๋ณํํด์ค ํ
- ํด๋น ๋ฉค๋ฒ๊ฐ ์์ผ๋ฉด home ๋ทฐํ ํ๋ฆฟ ํธ์ถํ๊ณ
- ํด๋น ๋ฉค๋ฒ๊ฐ ์์ผ๋ฉด model์ ํด๋น ๋ฉค๋ฒ๋ฅผ ๋ด๊ณ loginHome์ ํธ์ถํฉ๋๋ค.
@PostMapping("/logout")
public String logoutV2(HttpServletRequest request)
{
sessionManager.expire(request);
return "redirect:/";
}
// ์ธ์
๋ง๋ฃ
public void expire(HttpServletRequest request)
{
Cookie sessionCookie = findCookie(request,SESSION_COOKIE_NAME);
if(sessionCookie!=null)
{
sessionStore.remove(sessionCookie.getValue());
}
}
- loginHome์์ ๋ก๊ทธ์์ ๋ฒํผ ํด๋ฆญํ๋ฉด /logout URL ์์ฒญ โถ๏ธ request์์ SESSION_COOKIE_NAME("mySessionId")์ ์ฟ ํค๋ฅผ ์ฐพ๊ณ ๋งต์์ ์ญ์ ํฉ๋๋ค.
- ์ญ์ ๊ฐ ์๋ฃ๋๋ฉด ํ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํฉ๋๋ค.
๋ก๊ทธ์ธ ์ฒ๋ฆฌ - ์๋ธ๋ฆฟ HTTP ์ธ์
์ด๋ ๊ฒ ์ง์ ์ธ์ ์ ๊ตฌํํด๋ณด์๋๋ฐ, ์ฌ์ค ์ธ์ ์ด๋ผ๋ ๊ฒ๋ ๊ฒฐ๊ตญ ์ฟ ํค๋ฅผ ์ฌ์ฉํด ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
ํ๋ก์ ํธ๋ง๋ค ์ด๋ ๊ฒ ์ธ์ ๊ฐ๋ ์ ๊ฐ๋ฐํ๋ ๊ฒ๋ ์๋นํ ๋ถํธํ ๊ฒ์ ๋๋ค. ๊ทธ๋์ ์๋ธ๋ฆฟ๋ ์ธ์ ๊ฐ๋ ์ ์ ๊ณตํ๋๋ฐ ์๋ธ๋ฆฟ์ด ์ ๊ณตํ๋ ์ธ์ ์ ์ฌ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ๋์ ๋ฐฉ์์ ์ด์ ๊ณผ ๊ฑฐ์ ๋์ผํฉ๋๋ค.
์๋ธ๋ฆฟ์ด ์ ๊ณตํ๋ HttpSession์ ์ธ์ ์ ์์ฑ, ์กฐํ, ์ญ์ ์ญํ ์ ํฉ๋๋ค.
์ฆ, ์ง์ ๊ฐ๋ฐํ ๋ ์ฌ์ฉํ sessionManager์ ์ญํ ์ HttpSession์ผ๋ก ๋์ ํ ์ ์์ต๋๋ค.
login ์์ฒญ ์ปจํธ๋กค๋ฌ
@PostMapping("/login")
public String loginV3(@Valid @ModelAttribute LoginForm loginForm, BindingResult bindingResult,
HttpServletRequest request)
{
// Field, ํ์
์ค๋ฅ ๊ฒ์ฆ
if(bindingResult.hasErrors())
{
return "login/loginForm";
}
Member loginMember = loginService.login(loginForm.getLoginId(),loginForm.getPassword());
// ์คํจ
if(loginMember == null)
{
bindingResult.reject("loginFail","์์ด๋ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
return "login/loginForm";
}
// ์ฑ๊ณต์ฒ๋ฆฌ
// ์ธ์
์ด ์์ผ๋ฉด ์๋ ์ธ์
๋ฐํ, ์์ผ๋ฉด ์ ๊ท ์ธ์
์์ฑ
HttpSession session = request.getSession(true);
// ์ธ์
์ ๋ก๊ทธ์ธ ํ์ ์ ๋ณด ๋ณด๊ด
session.setAttribute(SessionConst.LOGIN_MEMBER,loginMember);
return "redirect:/";
}
// ์ธ์
๊ด๋ฆฌ์๋ฅผ ํตํด ์ธ์
์์ฑ -> ํ์๋ฐ์ดํฐ ๋ณด๊ด
sessionManager.createSession(loginMember,response);
์ด ์ ์ ์ฌ์ฉํ๋ sessionmanager์ ์ญํ ์ HttpSession์ ํตํด ์ฒ๋ฆฌํฉ๋๋ค.
// ์ฑ๊ณต์ฒ๋ฆฌ
// ์ธ์
์ด ์์ผ๋ฉด ์๋ ์ธ์
๋ฐํ, ์์ผ๋ฉด ์ ๊ท ์ธ์
์์ฑ
HttpSession session = request.getSession(true);
// ์ธ์
์ ๋ก๊ทธ์ธ ํ์ ์ ๋ณด ๋ณด๊ด
session.setAttribute(SessionConst.LOGIN_MEMBER,loginMember);
- request์ ์ธ์
์ด ์์ผ๋ฉด ๊ธฐ์กด ์ธ์
๋ฆฌํด, ์์ผ๋ฉด ์์ฑํด์ ๋ฆฌํด (true)
- false์ผ ๊ฒฝ์ฐ ์ธ์ ์ด ์์ผ๋ฉด ๊ธฐ์กด ์ธ์ ๋ฆฌํด, ์์ผ๋ฉด null ๋ฐํ
- ์ธ์
์ ๋ก๊ทธ์ธ ํ์ ์ ๋ณด๋ฅผ setAttribute๋ฅผ ํตํด ๋ณด๊ดํ๊ณ ํ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํฉ๋๋ค.
- ์ฌ๊ธฐ์ Session.LOGIN_MEMBER๋ HttpSession์ ์ธ์ ์ ๋ณด๊ดํ๊ณ ์กฐํํ ๋ ๊ฐ์ ์ด๋ฆ์ด ์ค๋ณต๋์ด ์ฌ์ฉ๋๋ฏ๋ก, ์์๋ฅผ "loginMember"๋ก ์ ์ํ์ต๋๋ค.
๋ก๊ทธ์ธ ํ ํ๋ฉด
@GetMapping("/")
public String homeLoginV3(HttpServletRequest request, Model model)
{
HttpSession session = request.getSession(false);
if(session==null)
{
return "home";
}
// ์ธ์
๊ด๋ฆฌ์์ ์ ์ฅ๋ ํ์ ์ ๋ณด ์กฐํ
Member loginMember = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER);
// ์ธ์
์ ํ์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด home์ผ๋ก ์ด๋
if(loginMember==null)
{
return "home";
}
// ์ธ์
์ด ์ ์ง๋๋ฉด ๋ก๊ทธ์ธ์ผ๋ก ์ด๋
model.addAttribute("member",loginMember);
return "loginHome";
}
- ๋ก๊ทธ์ธ ์์ ์ request์์ ์ธ์ ์ ์ฐพ๊ณ ์ธ์ ์ด ์์ผ๋ฉด home ๋ทฐํ ํ๋ฆฟ์ผ๋ก ์ด๋ํฉ๋๋ค.
- ์ธ์ ์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ ์์ ์ ์ธ์ ์ ๋ณด๊ดํ ํ์ ๊ฐ์ฒด๋ฅผ ์ฐพ์ต๋๋ค.
- ์ธ์ ๊ด๋ฆฌ์์ ์ ์ฅ๋ ํ์ ์ ๋ณด๋ฅผ ์กฐํํด ํด๋น ํ์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด home์ผ๋ก ์ด๋ํฉ๋๋ค.
- ์ธ์ ์ด ์ ์ง๋๋ฉด loginHome์ผ๋ก ์ด๋ํฉ๋๋ค.
๋ก๊ทธ์์ ์
@PostMapping("/logout")
public String logoutV3(HttpServletRequest request)
{
HttpSession session = request.getSession(false);
if(session!=null)
{
session.invalidate(); // ์ธ์
์ญ์
}
return "redirect:/";
}
- false์ต์ ์ ํตํด ์ธ์ ์ด ์๋๊ฒฝ์ฐ ๋ฆฌํด, ์์ผ๋ฉด null ๋ฆฌํด ( ์์ฑํ์ง ์์ )
- session์ด ์กด์ฌํ๋ฉด invalidate()๋ฅผ ํตํด ์ธ์ ์ ์ญ์ ํ๊ณ ํ ํ๋ฉด์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํฉ๋๋ค.
์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ HttpSession์ ์ด์ฉํด ์ง์ ๊ฐ๋ฐํ ์ธ์ ์ ๋์ฒดํด๋ณด์์ต๋๋ค.
์คํ๋ง์ ์ฌ๊ธฐ์ ๋ ๋์๊ฐ ์ธ์ ์ ๋ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก @SessionAttribute๋ฅผ ์ง์ํฉ๋๋ค.
@GetMapping("/")
public String homeLoginV3Spring(@SessionAttribute(name=SessionConst.LOGIN_MEMBER, required=false)
Member loginMember, Model model)
{
// ์ธ์
์ ํ์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด home์ผ๋ก ์ด๋
if(loginMember==null)
{
return "home";
}
// ์ธ์
์ด ์ ์ง๋๋ฉด ๋ก๊ทธ์ธ์ผ๋ก ์ด๋
model.addAttribute("member",loginMember);
return "loginHome";
}
@SessionAttribute๋ฅผ ํตํด ์ด๋ฏธ ๋ก๊ทธ์ธ ๋ ์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
์ธ์ ์ ์ฐพ๊ณ , ์ธ์ ์ ๋ค์ด์๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋ ๋ฒ๊ฑฐ๋ก์ด ๊ณผ์ ์ ์คํ๋ง์ด ํ๋ฒ์ ํธ๋ฆฌํ๊ฒ ์ฒ๋ฆฌํด ์ค ์ ์์ต๋๋ค.
HtttpSession์ ์ฌ์ฉํ ์ปจํธ๋กค๋ฌ๋ก ์ฒ์ ๋ก๊ทธ์ธ์ ์๋ํ๋ฉด ๋ก๊ทธ์ธ ํ ํ๋ฉด์
http://localhost:8080/;jsessionid=F59911518B921DF62D09F0DF8F83F872 ์ฒ๋ผ jessionid๋ฅผ ํฌํจํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ด๋ application.properties์ server.servlet.session.tracking-modes=cookie๋ฅผ ์ถ๊ฐํ๋ฉด URL ์ ๋ฌ ๋ฐฉ์ ์ฌ์ฉ์ ํด์ ํ ์ ์์ต๋๋ค.
์ธ์ ํ์์์ ์ค์ ๋ฐ ์ธ์ ์ ๋ณด ํ์ธ
@GetMapping("/session-info")
public String sessionInfo(HttpServletRequest request)
{
HttpSession session = request.getSession(false);
if(session==null)
{
return "์ธ์
์ด ์์ต๋๋ค.";
}
session.getAttributeNames().asIterator()
.forEachRemaining(name -> log.info("session name = {}, value = {}",name,session.getAttribute(name)));
log.info("sessionId={}", session.getId());
log.info("maxInactiveInterval={}", session.getMaxInactiveInterval());
log.info("creationTime={}", new Date(session.getCreationTime()));
log.info("lastAccessedTime={}", new Date(session.getLastAccessedTime()));
log.info("isNew={}", session.isNew());
return "์ธ์
์ถ๋ ฅ";
}
์ธ์ ์ ์ ํจ๊ธฐ๊ฐ์ application.properties์ server.servlet.session.timeout=60 ( ์ด ๋จ์ )์ ๊ฐ์ด ๊ธ๋ก๋ฒํ๊ฒ ์ค์ ํ ์๋ ์๊ณ ,
setMaxInactiveInterval์ ํตํด ์ธ์ ๋จ์๋ก ์ ํจ๊ธฐ๊ฐ์ ์ค์ ํ ์๋ ์์ต๋๋ค. ๊ฐฑ์ ์๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ ํจ๊ธฐ๊ฐ์ด ์ง๋๋ฉด ์ญ์ ๋ฉ๋๋ค.
session์ lastAccessdTime์ ๊ธฐ๋ฐ์ผ๋ก ์ ํจ๊ธฐ๊ฐ์ด ๊ฐฑ์ ๋ฉ๋๋ค.
<์ ๋ฆฌ>
- ์ง๊ธ๊น์ง ๋ก๊ทธ์ธ ๊ธฐ๋ฅ ๊ตฌํ๋ถํฐ ์ฟ ํค๋ฅผ ํตํ ์ฒ๋ฆฌ, ์ธ์ ์ ํตํ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํ, ์๋ธ๋ฆฟ์ด ์ ๊ณตํ๋ HttpSession์ ์ฌ์ฉํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ๊น์ง ํด๋ณด์์ต๋๋ค.
- ์๋ธ๋ฆฟ์ HttpSession์ด ์ ๊ณตํ๋ ํ์ ์์ ๊ธฐ๋ฅ ๋๋ถ์ ์ธ์ ์ ์์ ํ๊ณ ํธ๋ฆฌํ๊ฒ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ์ค๋ฌด์์ ์ฃผ์ํ ์ ์ ์ธ์ ์๋ ์ต์ํ์ ๋ฐ์ดํฐ๋ง ๋ณด๊ด *๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ด๊ณผ๋ก ์๋ฒ ์ฅ์ ๋ก ์ด์ด์ง ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard
'๐ Backend > MVC Pattern' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์คํ๋ง ์ธํฐ์ ํฐ(Interceptor) (0) | 2023.03.24 |
---|---|
Servlet Filter(์๋ธ๋ฆฟ ํํฐ) (0) | 2023.03.24 |
Bean Validation - ๊ฒ์ฆ ์ด๋ ธํ ์ด์ ์ฌ์ฉ (0) | 2023.03.22 |
์ค๋ฅ ์ฝ๋์ ๋ฉ์์ง ์ฒ๋ฆฌ (0) | 2023.03.21 |
๊ฒ์ฆ(Validation) ์ฒ๋ฆฌ ๋ฐฉ๋ฒ (0) | 2023.03.20 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422