커스텀 로그인 구현
CustomUserDetails 구현
CustomUserDetailsService 구현
로그인 사용자 정보 조회 방법
프로젝트 구조
GitHub 링크
UserDetails 설명
해당 인터페이스는 사용자 정보를 담는 기본적인 메서드들을 정의하고 있고, 주요 메서드로는 사용자의 이름, 패스워드, 권한 정보를 반환합니다. 커스텀해서 사용하는 이유는 기능이 제한적이고, 추가적인 회원 정보를 가져오기 위함이다.
CustomUserDetails.java
package com.example.login.dto;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.example.login.entity.Members;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public class CustomUserDetails implements UserDetails {
private final Members members;
// 권한 반환
@Override
public Collection getAuthorities() {
Collection collection = new ArrayList<>();
collection.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return members.getRole();
}
});
return collection;
}
// 비밀번호 반환
@Override
public String getPassword() {
//return members.getPassword();
return members.getLoginPwd();
}
// 아이디 반환
@Override
public String getUsername() {
//return members.getUsername();
return members.getLoginId();
}
// 계정 만료 여부 반환
@Override
public boolean isAccountNonExpired() {
return true;
}
// 계정 잠금 여부 반환
@Override
public boolean isAccountNonLocked() {
return true;
}
// 패스워드 만료 여부 반환
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 계정 사용 가능 여부 반환
@Override
public boolean isEnabled() {
return true;
}
}
UserDetailsService 설명
데이터베이스에서 사용자를 조회하고, 조회된 정보를 기반으로 UserDetails 객체를 생성하여 반환합니다. 반환된 UserDetails 객체는 Spring Security에서 인증 과정에서 사용됩니다.CustomUserDetailsService.java
package com.example.login.service;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.example.login.dto.CustomUserDetails;
import com.example.login.entity.Members;
import com.example.login.repository.MembersRepository;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final MembersRepository membersRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 회원 정보 조회
Members memberInfo = membersRepository.findByLoginId(username);
if (memberInfo != null) {
return new CustomUserDetails(memberInfo);
}
return null;
}
}
LoginController.java
package com.example.login.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class LoginController {
/**
* 로그인
* @return
*/
@GetMapping("/login")
public String login() {
return "login";
}
}
login.mustache
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>로그인</title>
<style>
.container {
width: 800px !important ;
}
</style>
</head>
<body>
<div class="container">
<form name="loginForm" method="post" action="/loginProc">
<div class="row">
<div class="col-md-12 pt-5">
<div class="card mb-4">
<h5 class="card-header text-center">로그인</h5>
<div class="card-body">
<div class="mb-3 row">
<label for="html5-text-input" class="col-md-2 col-form-label">아이디</label>
<div class="col-md-10">
<input class="form-control" type="text" id="loginId" name="loginId" />
</div>
</div>
<div class="mb-3 row">
<label for="html5-search-input" class="col-md-2 col-form-label">비밀번호</label>
<div class="col-md-10">
<input class="form-control" id="loginPwd" name="loginPwd" type="password" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<button type="submit" class="btn btn-outline-danger">로그인</button>
<a href="/" class="btn btn-outline-secondary">취소</a>
</div>
</div>
</form>
</div>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Controller 수정
MainController.java
package com.example.login.controller;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.example.login.dto.CustomUserDetails;
@Controller
public class MainController {
/**
* 메인
* @param customUserDetails
* @param model
* @return
*/
@GetMapping("/")
public String index(@AuthenticationPrincipal CustomUserDetails customUserDetails, Model model) {
// 로그인 여부 체크
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (!(principal instanceof String)) {
// 로그인 아이디
String id = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("========================");
System.out.println("아이디 : " + id);
System.out.println("========================");
// Membars 정보
System.out.println("========================");
System.out.println("아이디 : " + customUserDetails.getMembers().getLoginId());
System.out.println("닉네임 : " + customUserDetails.getMembers().getNickname());
System.out.println("권한 : " + customUserDetails.getMembers().getRole());
System.out.println("========================");
model.addAttribute("isLogin", true);
model.addAttribute("id", customUserDetails.getMembers().getLoginId());
model.addAttribute("nickname", customUserDetails.getMembers().getNickname());
}
else {
model.addAttribute("isLogin", false);
}
return "index";
}
}
index.mustache
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>메인 페이지</title>
<style>
.container {
width: 800px !important ;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12 pt-5">
<div class="card mb-4">
<h5 class="card-header text-center">메인 페이지</h5>
<div class="card-body">
{{#isLogin}}
<h5 class="card-title">{{nickname}}님 환영합니다.</h5>
<p class="card-text">접속하신 아이디는 {{id}} 입니다.</p>
{{/isLogin}}
{{^isLogin}}
<div class="col-md-12 text-center">
<a href="/join" class="btn btn-outline-primary">회원가입</a>
<a href="/login" class="btn btn-outline-success">로그인</a>
</div>
{{/isLogin}}
</div>
</div>
</div>
</div>
{{#isLogin}}
<div class="row">
<div class="col-md-12 text-center">
<a href="/logout" class="btn btn-outline-danger">로그아웃</a>
</div>
</div>
{{/isLogin}}
</div>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Spring Security Login | |
---|---|
2024.07.04 | [Spring Security] 커스텀 로그인 기능 구현하기 (3) |
2024.07.04 | [Spring Security] 커스텀 로그인 기능 구현하기 (2) |
2024.07.04 | [Spring Security] 커스텀 로그인 기능 구현하기 (1) |