티스토리 뷰

반응형

✏️  로그인 로직

  1. 로그인 창에서 아이디 + 비밀번호를 입력
  2. 컨트롤러는 LoginDTO로 이 값을 받아옴
  3. 컨트롤러는 멤버서비스를 통해 아이디가 존재하는지 비밀번호가 일치하는지 검사
  4. 일치한다면 로그인을 함과 동시에 authentication을 설정해주고, 세션을 만들어준 뒤 메인 화면으로 이동
  5. 일치하지 않는다면 로그 에러를 찍어주고 다시 로그인 화면을 띄어준다

✏️  LoginDTO 클래스

@Getter
@Setter

public class LoginDTO {
    private String id;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;
}

로그인 시 입력 값을 받아올 클래스이다.


✏️  login.html 생성

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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">
    <link rel="stylesheet" th:href="@{/css/main.css}">
    <title>로그인 창</title>
</head>
<body>
<h1>로그인을 해주세용</h1>
<img th:src="@{/image/html.png}">
<form method="post" action="/member/login" class="login-box">
    <table id="login-table">
        <tr>
            <td>아이디 <input type="text" name="id" required/></td>
        </tr>
        <tr>
            <td>비밀번호 <input type="text" name="password" required   autocomplete="off"/></td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="로그인">
            </td>
        </tr>
    </table>
</form>
</body>
</html>

✏️  Api Controller 클래스

@PostMapping("/login")
public String login(LoginDTO loginDTO, HttpServletRequest httpServletRequest) {
    boolean isMemberExist = memberService.checkMemberExist(loginDTO.getId());
    if (!isMemberExist) {
        log.error("아이디가 존재하지 않음");
        return "redirect:/login";
    }
    boolean isLoginSamePassword = memberService.checkLoginSamePassword(loginDTO);
    if (!isLoginSamePassword) {
        log.error("비밀번호가 일치하지 않음");
        return "redirect:/login";
    }

    log.info("login success");

    httpServletRequest.getSession().invalidate();
    HttpSession session = httpServletRequest.getSession();
    session.setAttribute("userId", loginDTO.getId());
    session.setMaxInactiveInterval(1800);
    log.info("세션 생성");
    return "redirect:/member/list";

}

로그인 창에 아이디와 비밀번호를 입력하면 Api 컨트롤러가 LoginDTO를 통해 입력 값을 받아오고 아이디가 db에 존재하는지, 비밀번호가 db랑 일치하는지 검사를 한 후 일치한다면 세션을 만들어서 인증을 해준다.


✏️  WebController 클래스

@GetMapping("/login")
public String login(HttpServletRequest httpServletRequest) {
    HttpSession session = httpServletRequest.getSession();
    Optional<Object> idOptional =Optional.ofNullable(session.getAttribute("userId"));
    if(idOptional.isPresent()){
        return "redirect:/member/list";
    }
    return "login";
}

✏️  MemberService 인터페이스

public interface MemberService {
	boolean checkLoginSamePassword(LoginDTO loginDTO);
}

✏️  MemberServiceImpl 클래스

  @Override
  public boolean checkLoginSamePassword(LoginDTO loginDTO) {
      UserDetails member = memberDetailService.loadUserByUsername(loginDTO.getId());
      if (!(passwordEncoder.matches(loginDTO.getPassword(), member.getPassword()))) {
          log.error("비밀번호가 일치하지 않습니다.");
          return false;
      }
      return true;
  }

MemberService에 새롭게 추가된 checkLoginSamePassword 메소드를 구현해준다. 입력한 비밀번호가 db에 있는지 검사해준다


✏️  MemberDetailService 클래스

@Service
@RequiredArgsConstructor
@Slf4j
public class MemberDetailService implements UserDetailsService {

    private final MemberRepository memberRepository;
    private static final Logger log = LoggerFactory.getLogger(MemberServiceImp.class);

    @Override
    public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
        Optional<Member> memberEntity = memberRepository.findById(id);
        Member member = memberEntity.get();
        return new MemberDetail(member);
    }
}

그냥 로그인을 해도 되지만 이렇게 하는 이유는 MemberDetail(member) 를 함으로써 authentication을 설정해 줄 수 있도록 해준다. 우리가 인터넷상에서 메일을 보내고 블로그를 쓰는 등의 행위는 권한이 필요한데 이 권한을 추가해준다


✏️  UserDetailService 인터페이스

public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

✏️  MemberDetail 클래스

package hello.hello_spring.service;

import hello.hello_spring.domain.member.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@RequiredArgsConstructor
public class MemberDetail implements UserDetails {



    private final Member member;

    @Override
    public boolean isAccountNonExpired() {
        return UserDetails.super.isAccountNonExpired();
    }

    @Override
    public boolean isAccountNonLocked() {
        return UserDetails.super.isAccountNonLocked();
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return UserDetails.super.isCredentialsNonExpired();
    }

    @Override
    public boolean isEnabled() {
        return UserDetails.super.isEnabled();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_" + member.getRole().name()));
        return authorities;
    }

    @Override
    public String getPassword() {
        return member.getPassword();
    }

    @Override
    public String getUsername() {
        return member.getId();
    }
}

UserDetails 인터페이스를 상속받아 구현하는 클래스로 중요한 부분은 밑에서 3번째 함수이다. 로그인을 할 때 ContextHolder → Authentication → 의 authories에 권한을 추가해준다.

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함