로그인
사용자 인증 과정 중 하나로, 사용자가 입력한 아이디와 비밀번호가 데이터베이스에 저장된 회원정보와 일치하는지 확인하는 것이다. 일치하는 경우, 웹 어플리케이션은 해당 사용자의 정보를 Session 객체에 저장하여 유지한다. 이후, 사용자의 요청에 대해 해당 세션 정보를 참조하여 인증된 사용자임을 확인하고 적절한 서비스를 제공한다.
* Session 객체
서버 측에서 클라이언트의 상태를 유지하기 위한 객체로, 사용자가 로그인을 하거나 어떤 정보를 제출하면 그 정보를 받아 처리한 후 , 사용자에게 할당된 고유한 세선 ID를 생성한다. 이 세선 ID는 쿠키나 URL 매개변수(parameter)를 통해 클라이언트에게 전달되어, 이후 클라이언트가 서버에 요청을 보낼 때마다 세선 ID를 함께 보낸다.
1. Servlet
package edu.kh.community.member.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import edu.kh.community.member.model.service.MemberService;
import edu.kh.community.member.model.vo.Member;
// --------------------------------------------
@WebServlet("/member/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 전달된 파라미터 변수에 저장
String inputEmail = req.getParameter("inputEmail");
String inputPw = req.getParameter("inputPw");
// 사용자로부터 입력받은 정보인 inputEmail, inputPw를 Member객체의 meberEmail과 memberPw에 세팅
// (Mebmer객체는 VO클래스로 데이터베이스 테이블과 1:1 매핑)
Member mem = new Member();
mem.setMemberEmail(inputEmail);
mem.setMemberPw(inputPw);
try {
// 서비스 객체 생성
MemberService service = new MemberService();
// 이메일, 비밀번호가 일치하는 회원을 조회하는 서비스 호출 후 결과 반환 받기
Member loginMember = service.login(mem);
// Session 객체 얻어오기
HttpSession session = req.getSession();
if(loginMember != null) { // 성공
// 회원 정보를 Session에 세팅
session.setAttribute("loginMember", loginMember);
// 세션 만료: 특정 시간동안 요청 없으면 세션 만료
session.setMaxInactiveInterval(3600); // 초
// 쿠키 객체 생성
Cookie c = new Cookie("saveId", inputEmail);
// 아이디 저장이 체크된 경우
if(req.getParameter("saveId") != null){
// 쿠키 파일을 30일간 유지
c.setMaxAge(60*60*24*30);//초단위
} else { // 체크 안했을 때 ( 체크 O -> 체크해제 했을 때 )
// 쿠키 파일을 0초 동안 유지
// -> 기존에 존재하던 쿠키 파일의 유지 시간을 0초로 덮어 씌움 = 삭제하겠다.
c.setMaxAge(0);
}
// 해당 쿠키 파일이 적용될 주소를 지정
// 최상위 주소로 시작하는 주소에서만쿠키 적용
c.setPath(req.getContextPath());
// 응답 객체를 이용해서 클라이언트로 전달
resp.addCookie(c);
} else { // 실패
session.setAttribute("message", "아이디 또는 비밀번호가 일치하지 않습니다.");
}
// sednRedirect(): 이전 요청(req)에서 보낸 HTTP 응답(resp)을 다시 보낼 때 사용
// 웹 브라우저는 새로운 요청을 보내고 새로운 URL로 이동
// 이동한 URL은 반드시 절대경로 혹은 전체 URL
resp.sendRedirect(req.getContextPath());
} catch (Exception e) {
e.printStackTrace();
}
}
}
* HttpSession 객체
- 클라이언트와 서버 간의 상태 정보를 유지하기 위한 객체로, 일반적으로 사용자 인증 정보나 세션데이트 덩을 저장하고 관리함
- 만약, 현재 요청에 대한 HttpSession객체가 이미 존재한다면, 해당 객체를 반환하고 없다면 새로운 HttpSession객체 생성하고, 이후 HttpSession 객체는 session 변수에 할당되어 사용될 수 있음
- HttpSession 객체를 사용하면, 사용자가 로그인한 상태를 유지하거나, 쇼핑몰 장바구니 등 데이터를 관리하는 다양한 기능을 구현할 수 있으며, HttpSession 객체를 사용하는 것은 쿠키를 사용하는 것보다 보안적으로 안전하며 서버측에서 직접 관리하여 보안에 강함
* 아이디 저장(Cookie)
- Cookie: 클라이언트(브라우저)에서 관리하는 파일로, 특정 주소 요청 시마다 해당 주소와 연관된 쿠키 파일을 브라우저가 알아서 읽어오며, 읽어온 쿠키 파일의 내용을 서버에 같이 전달한다.
<생성 및 사용 방법>
① 서버가 요청에 대한 응답을 할 때, 쿠키를 생성한 후 응답에 쿠키를 담아 클라이언트에게 전달
② 응답에 담긴 쿠키가 클라이언트에게 파일 형태로 저장
③ 이후 특정 주소 요청 시 쿠키 파일을 브라우저가 찾아 자동으로 요청에 실어서 보냄
④ 서버는 요청에 실려온 쿠키파일을 전송
* 요청
1. forward: 요청 위임(로그인의 경우 딱히 응답해야 할 페이지가 없음)
- Servlet으로 응답화면을 만들기가 불편하기 때문에 req, resp 객체를 위임 하여 요청에 대한 응답화면을 대신 만듦
2. redirect: 재요청
- 현재 Servlet에서 응답 페이지를 만들지 않고 응답페이지를 만들 수 있는 다른 요청의 주소로 클라이언트를 이동시킴(재요청)
- redirect 시 request 객체가 유치되지 않기 때문에 특정 데이터를 전달하거나 유지하고 싶으면 session 또는 application 범위에 세팅해야 함
2. Service
package edu.kh.community.member.model.service;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import static edu.kh.community.common.JDBCTemplate.*;
import edu.kh.community.member.model.dao.MemberDAO;
import edu.kh.community.member.model.vo.Member;
// ---------------------------------------------
public class MemberService {
private MemberDAO dao = new MemberDAO();
/** 로그인 서비스
* @param mem
* @return
*/
public Member login(Member mem) throws Exception {
// Connection 얻어오기
Connection conn = getConnection();
// DAO 수행(mem: email, pw)
Member loginMember = dao.login(conn, mem);
// Connection 반환
close(conn);
// 결과 반환
return loginMember;
}
3. DAO
package edu.kh.community.member.model.dao;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import static edu.kh.community.common.JDBCTemplate.*;
import edu.kh.community.member.model.vo.Member;
//------------------------------------------------
public class MemberDAO {
private Statement stmt;
private PreparedStatement pstmt;
private ResultSet rs;
private Properties prop;
public MemberDAO() {
try {
prop = new Properties();
String filePath = MemberDAO.class.getResource("/edu/kh/community/sql/member-sql.xml").getPath();
prop.loadFromXML( new FileInputStream(filePath) );
} catch(Exception e) {
e.printStackTrace();
}
}
/** 로그인 서비스
* @param conn
* @param mem
* @return
* @throws SQLException
*/
public Member login(Connection conn, Member mem) throws SQLException {
// 결과 저장용 변수 선언
Member loginMember = null;
try {
//SQL 얻어오기(entry key: login)
String sql = prop.getProperty("login");
//PreparedStatement 생성 및 SQL 적재
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, mem.getMemberEmail());
pstmt.setString(2, mem.getMemberPw());
// SQL 수행 (db로 보냈다 조회결과 가져와서 넣음)
rs = pstmt.executeQuery();
/* 수행할 SQL
<entry key="login">
SELECT MEMBER_NO, MEMBER_EMAIL, MEMBER_NICK, MEMBER_TEL,
MEMBER_ADDR, PROFILE_IMG,
TO_CHAR(ENROLL_DT, 'YYYY-MM-DD HH24:MI:SS') AS ENROLL_DT
FROM MEMBER
WHERE MEMBER_EMAIL = ?
AND MEMBER_PW = ?
AND SECESSION_FL = 'N'
</entry>
*/
// 얻어온 결과가 하나, if문 사용
if(rs.next()) {
loginMember = new Member();
loginMember.setMemberNo( rs.getInt("MEMBER_NO") );
loginMember.setMemberEmail( rs.getString("MEMBER_EMAIL") );
loginMember.setMemberNickname( rs.getString("MEMBER_NICK") );
loginMember.setMemberTel( rs.getString("MEMBER_TEL") );
loginMember.setMemberAddress( rs.getString("MEMBER_ADDR") );
loginMember.setProfileImage( rs.getString("PROFILE_IMG") );
loginMember.setEnrollDate( rs.getString("ENROLL_DT") );
}
} finally {
close(rs);
close(pstmt);
}
return loginMember;
// 결과: null or member 객체 주소
}
'Sever' 카테고리의 다른 글
6. 이메일 중복 검사 및 인증번호 이메일 보내기 기능 구현하기 (0) | 2023.04.05 |
---|---|
4. JDBC - 연결 생성부터 자원반환까지 (0) | 2023.04.04 |
3. JDBC의 흐름 및 JDBC Tamplate (0) | 2023.04.04 |
2. JSP? + AJAX? (0) | 2023.03.28 |
1. Sevlet? (0) | 2023.03.27 |