관리자 로그인 실습 준비와 화면 구현
앞서 관리자 회원가입 기능을 구현했다. 이번에는 관리자 로그인 기능을 구현해본다.
① 관리자 로그인 화면을 구현한다.
② 관리자 로그인 인증을 처리하기 위한 컨트롤러, 서비스, DAO을 구현한다.
③ 쿠키를 이용한 로그인 상태 유지 및 로그아웃 기능을 구현한다.
④ 세션을 이용한 로그인 상태 유지 및 로그아웃 기능을 구현한다.
⑤ 일반 관리자를 로그인할 수 있도록 승인한다.
⑥ 최고 관리자와 일반 관리자를 구분해서 메뉴를 구성한다.
최고 관리자와 일반 관리자
· 최고 관리자(super admin)은 회원가입 직후 바로 로그인이 가능하지만, 일반 관리자는 회원 가입 후 최고 관리자의 승인이 완료되어야 로그인이 가능하다.
일반 관리자 추가하기
· 일반 관리자(admin1)을 추가해본다.
· 일반 관리자(admin1)는 a_m_approval값이 0으로 최고 관리자(super admin)의 승인 전이다.
따라서 회원가입은 했으나 아직 로그인이 불가능한 상태이다.
관리자 로그인 화면 구현하기
· 관리자 로그인에 대한 링크는 nav.jsp에 있다.
· 경로 : webapp\WEB-INF\views\admin\include\nav.jsp
서버에서 클라이언트의 /loginForm 요청을 처리하기 위해 AdminMemberController에 메서드를 만들고 URL를 매핑한다.
다음과 같이 AdminMemberController에 loginForm()을 추가해본다.
· loginForm()은 /loginForm 요청이 발생하면 [admin/member] 폴더에 있는 login_form.jsp 파일을 이용해서 뷰를 만들고 클라이언트에 응답을 할 뿐 서비스 또는 DAO를 이용하지 않는 단순한 구조이다.
■ AdminMemberController 코드
// 로그인
@GetMapping("/loginForm")
public String loginForm() {
System.out.println("[AdminMemberController] loginForm()");
String nextPage = "admin/member/login_form";
return nextPage;
}
· login_form.jsp는 관리자 아이디(a_m_id)와 비밀번호(a_m_pw)를 입력할 수 있고, <login> 버튼을 클릭하면 <form>의 action에 명시한 /admin/member/loginConfirm을 이용해서 서버로 로그인 인증을 요청한다.
■ login_form.jsp 코드
관리자 로그인 처리 기능 구현
컨트롤러 구현하기
클라이언트의 /loginConfirm 요청을 처리하기 위해 AdminMemberController에 login Confirm()을 선언한다.
· /loginConfirm 요청을 loginConfirm()에 매핑하고 AdminMemberVo를 파라미터로 받는다.
· AdminMemberVo에는 관리자가 입력한 아이디(a_m_id)와 비밀번호(a_m_pw) 정보가 저장되어 있다.
· loginConfirm()에서 관리자 로그인 인증에 성공하면 [admin/member] 폴더에 있는 login_ok.jsp를 이용해서 View를 만들고 클라이언트에 '관리자 로그인 성공'을 응답한다.
· AdminMemberService에 관리자 로그인 인증 업무를 지시하기 위해 loginConfirm()을 호출한다. 이때 매개변수로 받은 adminMemberVo를 함께 전달한다.
· 만약 adminMemberService가 null을 반환하면, 관리자 로그인에 실패한 경우로 [admin/member] 폴더에 있는 login_ng.jsp를 이용해서 View를 만들고 클라이언트에게 '관리자 로그인 실패'를 응답한다.
■ AdminMemberController 코드
// 로그인 확인
@PostMapping("/loginConfirm")
public String loginConfirm(AdminMemberVo adminMemberVo) {
System.out.println("[AdminMemberController] loginConfirm()");
String nextPage = "admin/member/login_ok";
AdminMemberVo loginedAdminMemberVo =
adminMemberService.loginConfirm(adminMemberVo);
if (loginedAdminMemberVo == null) {
nextPage = "admin/member/login_ng";
}
return nextPage;
}
서비스 구현하기
관리자 로그인 인증을 하기 위해 위에 컨트롤러에서 서비스의 loginConfirm()을 호출한다.
따라서 이에 따른 AdminMemberService에 loginConfirm()을 선언해준다.
· 서비스는 로그인 인증을 처리하기 위해 관리자가 입력한 정보(아이디, 비밀번호)와 일치하는 관리자가 데이터베이스(tbl_admin_member 테이블)에 있는지 확인해야 한다.
따라서 서비스는 DAO를 이용해야 하며, AdminMemberDao의 selectAdmin()을 이용해야 한다.
· selectAdmin()이 반환되는 회원정보는 loginedAdminMemberVo에 담긴다.
만약, loginedAdminMemberVo가 null이면 관리자가 입력한 정보와 일치하는 관리자가 없다.
■ AdminMemberService 코드
public AdminMemberVo loginConfirm(AdminMemberVo adminMemberVo) {
System.out.println("[AdminMemberService] loginConfirm()");
AdminMemberVo loginedAdminMemberVo =
adminMemberDao.selectAdmin(adminMemberVo);
if (loginedAdminMemberVo != null)
System.out.println("AdminMemberService] ADMIN MEMBER LOGIN SUCCESS!!");
else
System.out.println("AdminMemberService] ADMIN MEMBER LOGIN FAIL!!");
return loginedAdminMemberVo;
}
DAO 구현하기
로그인하려는 관리자가 입력한 정보(아이디, 비밀번호)와 일치하는 관리자를 tbl_admin_member 테이블에서 조회하기 위한 selectAdmin()을 AdminMemberDao에 선언한다.
■ AdminMemberDao 코드
public AdminMemberVo selectAdmin(AdminMemberVo adminMemberVo) {
System.out.println("[AdminMemberDao] selectAdmin()");
String sql = "SELECT * FROM tbl_admin_member "
+ "WHERE a_m_id = ? AND a_m_approval > 0";
List<AdminMemberVo> adminMemberVos = new ArrayList<AdminMemberVo>();
try {
adminMemberVos = jdbcTemplate.query(sql, new RowMapper<AdminMemberVo>() {
@Override
public AdminMemberVo mapRow(ResultSet rs, int rowNum) throws SQLException {
AdminMemberVo adminMemberVo = new AdminMemberVo();
adminMemberVo.setA_m_no(rs.getInt("a_m_no"));
adminMemberVo.setA_m_approval(rs.getInt("a_m_approval"));
adminMemberVo.setA_m_id(rs.getString("a_m_id"));
adminMemberVo.setA_m_pw(rs.getString("a_m_pw"));
adminMemberVo.setA_m_name(rs.getString("a_m_name"));
adminMemberVo.setA_m_gender(rs.getString("a_m_gender"));
adminMemberVo.setA_m_part(rs.getString("a_m_part"));
adminMemberVo.setA_m_position(rs.getString("a_m_position"));
adminMemberVo.setA_m_mail(rs.getString("a_m_mail"));
adminMemberVo.setA_m_phone(rs.getString("a_m_phone"));
adminMemberVo.setA_m_reg_date(rs.getString("a_m_reg_date"));
adminMemberVo.setA_m_mod_date(rs.getString("a_m_mod_date"));
return adminMemberVo;
}
}, adminMemberVo.getA_m_id());
if (!passwordEncoder.matches(adminMemberVo.getA_m_pw(), adminMemberVos.get(0).getA_m_pw()))
adminMemberVos.clear();
} catch (Exception e) {
e.printStackTrace();
}
return adminMemberVos.size() > 0 ? adminMemberVos.get(0) : null;
}
[코드 설명]
· selectAdmin()은 서비스에서 넘겨준 adminMemberVo를 이용해서 아이디와 비밀번호가 일치하는 관리자를 tbl_admin_member 테이블에서 조회하고, 결과를 AdminMemberVo 타입으로 서비스에 반환한다.
· 조회한 회원 정보를 저장하는 List로 일치하는 회원이 검색된 경우 adminMemberVos의 길이는 1이고, 그렇지 않은 경우 0이 된다.
String sql = "SELECT * FROM tbl_admin_member " + "WHERE a_m_id = ? AND a_m_approval > 0";
다음 코드는 tbl_admin_member 테이블에서 관리자를 조회하는 쿼리로, 관리자가 입력한 아이디가 a_m_id(관리자 아이디)와 일치하고 a_m_approval(관리자 승인)이 완료(1)된 회원을 조회한다는 내용이다.
adminMemberVos = jdbcTemplate.query(sql, new RowMapper<AdminMemberVo>() {
@Override
public AdminMemberVo mapRow(ResultSet rs, int rowNum) throws SQLException {
AdminMemberVo adminMemberVo = new AdminMemberVo();
....
return adminMemberVo;
}
}, adminMemberVo.getA_m_id());
데이터베이스에 저장되어 있느 비밀번호는 암호화된 문자열로 관리자가 입력한 비밀번호와 비교할 수 없다.
따라서 JdbcTemplate의 query()를 이용해서 회원을 조회하는 쿼리를 실행하고 결과를 adminMemberVos에 할당한다.
· query()는 3개의 파라미터를 받는다.
query(쿼리문, RowMapper 인터페이스를 구현한 익명 클래스, 관리자가 입력한 아이디)
- RowMapper 인터페이스를 구현한 클래스: 데이터베이스의 row(행)을 어딘가 매핑하는 역할
- row: VO(AdminMemberVo) 객체에 매핑
public AdminMemberVo mapRow(ResultSet rs, int rowNum)
RowMapper를 구현한 익명 클래스는 RowMapper의 추상 메서드를 구현해야 하는 의무가 있는데, 바로 mapRow()이다.
· mapRow() : ResultSet과 행의 개수를 파라미터로 받는다.
· rs : 데이터베이스에서 조회된 데이터셋이 저장
· rowNum : 데이터셋의 현재 행 번호가 저장
따라서 mapRow()에서 조회된 데이터를 Java 데이터 형식으로 변경하는데 사용되는 데이터 형식의 객체가 AdminMemberVo이다.
AdminMemberVo adminMemberVo = new AdminMemberVo();
adminMemberVo.setA_m_no(rs.getInt("a_m_no"));
...
adminMemberVo.setA_m_mod_date(rs.getString("a_m_mod_date"));
return adminMemberVo;
AdminMemberVo 객체를 생성하고 rs에 있는 데이터를 AdminMemberVo 객체의 setter를 이용해서 저장한다.
모든 데이터의 저장(set)이 끝나면 AdminMemberVo 객체를 반환한다.
반환된 객체는 List 타입으로 저장된 후 adminMemberVos에 할당된다.
if (!passwordEncoder.matches(adminMemberVo.getA_m_pw(), adminMemberVos.get(0).getA_m_pw()))
adminMemberVos.clear();
다음은 관리자가 입력한 비밀번호와 RowMapper에 의해서 VO에 매핑된 비밀번호를 비교하는 코드이다.
· PasswordEncoder의 matches()
- 암호화된 문자열을 비교하는 메서드
- 암호화된 비밀번호를 복호화해서 관리자가 입력한 비밀번호와 비교 연산하고 결과를 반환
형식 : matches(암호화되지 않은 비밀번호(관리자가 입력한 비밀번호), 암호화된 비밀번호(데이터베이스의 비밀번호))
비교 결과가 false라면 관리자가 입력한 비밀번호가 일치하지 않은 것으로 판단해 조회된 데이터(adminMemberVo)는 삭제(adminMemberVos.clear())한다.
return adminMemberVos.size() > 0 ? adminMemberVos.get(0) : null;
adminMemberVos의 길이가 0보다 크면 로그인 인증에 성공한 경우로 조회된 관리자 정보를 서비스에 반환한다.
- 로그인 성공하면 adminMemberVos의 길이는 항상 1이다.
adminMemberVos의 길이가 0이하라면 로그인 인증에 실패한 경우로 서비스에 null을 반환한다.
관리자 로그인 결과 확인
1. 최고 관리자 로그인 및 결과 확인
![]() |
![]() |
관리자 홈 > 로그인 양식 > 로그인 인증(컨트롤러) > 로그인 인증(서비스) > 관리자 조회 > 조회에 따른 로그인 인증 결과 출력
2. 일반 관리자 로그인 및 결과 확인
![]() |
![]() |
일반 관리자는 최고 관리자 승인 전에는 로그인이 불가능한 것을 확인했다.
'Spring & Springboot > 올인원 스프링 프레임워크' 카테고리의 다른 글
전자 도서관 프로젝트 - 일반 관리자 승인 처리 기능 구현 (0) | 2023.10.12 |
---|---|
전자 도서관 프로젝트 - 로그인 상태 유지 및 로그아웃 기능 구현 (0) | 2023.10.11 |
전자 도서관 프로젝트 - 데이터베이스 연동 (0) | 2023.10.07 |
전자 도서관 프로젝트 - 관리자 회원가입 기능 구현 (0) | 2023.10.06 |
전자 도서관 프로젝트 - 설계 및 생성하기 (0) | 2023.10.05 |