세션 로그인 구현 복습
저번 프로젝트 때는 세션을 활용해 로그인을 구현했었다.
당시에는 서비스를 배포까지 계획이 없었기 때문에 세션으로도 충분했다.
하지만 굉장히 대충 만든 로그인이었고 이번 프로젝트에서는 JWT 방법을 이용하고자 한다.
또한 가능하다면 카카오/구글 등으로도 로그인을 가능하게 구현하는 것이 목표이다.
JWT 로그인 구현 방식에 대해 간략하게 찾아보니... 대충 봐도 어려웠다.
이왕 공부하는거 세션 로그인부터 시작해서 총체적으로 정리해야겠다.
저번 프로젝트 때 로그인은 아래와 같은 코드로 구현했다.
1. controller
@Controller
public class LoginController {
private LoginService service;
@Autowired
public LoginController(LoginService service) {
this.service = service;
}
@GetMapping(value="/login")
public String login(HttpServletRequest request) {
return "login";
}
@PostMapping(value="/loginok")
public void loginok(HttpSession session, HttpServletResponse resp, HttpServletRequest req, LoginDTO dto, Model model) {
LoginDTO result = service.login(dto);
try {
if (result != null) {
session.setAttribute("result", result);
resp.sendRedirect("/web/dashboardall");
} else {
session.removeAttribute("result");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<script>alert('아이디 또는 비밀번호가 틀렸습니다.'); location.href='/web/login';</script>");
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@GetMapping(value="/logout")
public String logout(HttpSession session, HttpServletRequest req) {
session.removeAttribute("result");
return "redirect:/login";
}
}
2. DAO
public interface LoginDAO {
LoginDTO login(LoginDTO dto);
}
3. DAOImpl
@Repository
public class LoginDAOImpl implements LoginDAO {
private SqlSessionTemplate template;
@Autowired
public LoginDAOImpl(SqlSessionTemplate template) {
this.template = template;
}
@Override
public LoginDTO login(LoginDTO dto) {
return this.template.selectOne("login.login", dto);
}
}
4. DTO
import lombok.Data;
@Data
public class LoginDTO {
private String employeeseq;
private String ename;
private String role;
private String email;
private String pw;
private String position;
private String tname;
private String pname;
private String pjsdate;
private String pjfdate;
private String pstate;
private String levelseq;
}
5. Service
public interface LoginService {
LoginDTO login(LoginDTO dto);
}
6. ServiceImpl
@Service
public class LoginServiceImpl implements LoginService {
private LoginDAO dao;
@Autowired
public LoginServiceImpl(LoginDAO dao) {
this.dao = dao;
}
@Override
public LoginDTO login(LoginDTO dto) {
return dao.login(dto);
}
}
HttpSession을 이용해 로그인을 구현했고 장점은 HttpSession을 필요할 때만 생성하는 것이 가능하다는 점이다.
로그아웃하면 해당 세션을 제거하고 다시 로그인 페이지로 이동하도록 코드를 작성했다.
이 세션 정보를 이용해서 로그인한 사람의 직책에 따라 다른 메뉴가 보이도록 jsp 코드를 작성했다.
이런 부분을 구현하기 위해 처음 로그인 시 세션에 최대한 많은 정보를 저장했다.
구현하다가 필요한 정보가 있으면 DB 조합으로 만드는 게 아니라 세션에 정보를 추가했다.
보안 등 여러 요소를 고려하지 않았고 일단 로그인이 되는기 위한 코드였다.
그러다 보니 이 과정에서 공부하고 배운 것이 없는 것 같다.
<!-- 관리자 -->
<li class="nav-item admin">
<a class="nav-link collapsed admin" data-toggle="collapse" data-target="#collapseAdmin" aria-expanded="true" aria-controls="collapseAdmin">
<i class="fas fa-fw fa-cog admin"></i> <span class="admin">관리자</span>
</a>
<div id="collapseAdmin" class="collapse" aria-labelledby="headingOne" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<a class="collapse-item " href="/web/adminuser">사용자 관리</a>
<a class="collapse-item " href="/web/adminproject">프로젝트 관리</a>
</div>
</div>
</li>
<script>
$(function() {
var role = "${sessionScope.result.role}";
var levelseq = "${sessionScope.result.levelseq}";
if (levelseq == 1) {
$(".admin").show();
} else {
$(".admin").hide();
}
if (role == "PL") {
$(".adminProject").show();
} else {
$(".adminProject").hide();
}
});
</script>
로그인 상태 유지하는 2가지 방법
1. 요청할 때 사용자 정보를 쿼리 파라미터로 전달하기
> 번거롭고 식별 가능한 사용자 정보를 쿼리 파라미터에 노출하는 것은 보안상 위험하다.
2. 쿠키에 사용자 정보 담아서 사용하기
> 서버에서 로그인 성공 시 HTTP 응답에 쿠키를 담아 브라우저에 전달, 브라우저는 쿠키를 지속적으로 서버에 보내서 서버는 사용자를 식별할 수 있다.
3. 쿠키에 세션 정보 담아서 사용하기
쿠키 종류
1. 영속 쿠키 : 만료 날짜까지 유지
2. 세션 쿠키 : 브라우저 종료 시까지만 유지
쿠키의 보안 문제
1. 쿠키 값은 임의로 변경 가능하다
> 클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 됨
> 웹브라우저 개발자 모드 Application Cookie 변경으로 확인 가능
2. 쿠키에 보관된 정보를 훔쳐갈 수 있다.
> 쿠키에 개인 정보 등이 있다면 이 정보가 웹 브라우저에 보관되고 네트워크 요청마다 계속 클라이언트 서버로 전달됨
> 쿠키의 정보가 나의 로컬 PC 혹은 네트워크 전송 구간에서 해킹당할 수 있다.
3. 해커가 쿠키를 훔쳐가면 평생 사용할 수 있다.
* 지금까지 내가 말하는 session과 쿠키는 같은 것? 세션 쿠키 / 영속 쿠키였던 것 같다
> 네트워크에 대한 지식이 없어 모르는 것 같다. 적어도 이 부분은 찾아서 정리 하기
* 보통은 세션 정보를 쿠키에 저장해 로그인을 구현하는 것 같다
> 이 방법으로 다시 구현해 보기
* 스프링 시큐리티를 이용해 로그인을 구현하는 것도 좋은 방법인 것 같다
참고
https://develop-writing.tistory.com/m/87
https://catsbi.oopy.io/0c27061c-204c-4fbf-acfd-418bdc855fd8
https://jaehoney.tistory.com/67