암호화를 하기 전에 가입된 데이터는 패스워드가 암호화되어 있지 않습니다. 이 기능은 spring securtiy와 상관없이 암호화되지 않은 전 사원의 패스워드를 암호화하기 위해 추가한 기능입니다.
admin의 권한을 갖고 있는 사원만 접근할 수 있으며 실행하면 전사원의 비밀번호를 암호화 할 수 있는 페이지가 실행되며 패스워드를 암호화하고 싶은 사원을 체크하고 [비밀번호변경] 버튼을 누르면 선택한 사원의 패스워드가 암호화될 수 있도록 처리하도록 하겠습니다.
위의 작업을 수행하기 위해서는 사원 전체 목록을 출력할 수 있어야 하며 체크박스로 선택한 사원의 모든 패스워드를 암호화하여 update 할 수 있어야 합니다.
암호화하면 문자열이 길어지므로 컬럼의 사이즈를 수정하고 작업합니다.
[step01 - 전체 회원목록 출력하기]
관리자 페이지 왼쪽 메뉴에서 [비밀번호변경] 을 클릭하면 전 사원의 목록이 다음과 같이 출력되어야 합니다.
관리자의 기능이므로 ktds.erp.admin패키지를 추가하고 작업합니다.
emp.xml
전 사원을 조회할 수 있도록 emp.xml mapper에 다음과 같이 <select> 태그를 추가합니다.
<select id="selectAll" resultType="emp">
select * from member
</select>
AdminDAO
package ktds.erp.admin;
import java.util.ArrayList;
import java.util.List;
import ktds.erp.emp.MemberDTO;
public interface AdminDAO {
//전체 사원을 조회하기
List<MemberDTO> getMemberList();
//암호화하기 위해 체크한 사원의 목록을 조회하기
List<MemberDTO> getCheckList(ArrayList<String> idlist);
//암호화하기 위해 체크한 사원의 비밀번호를 암호화한 비밀번호로 업데이트하기
int update(List<MemberDTO> userlist);
}
AdminDAOImpl
전체 사원 목록을 조회할 mapper의 아이디를 정의하고 실행될 수 있도록 코드를 작성합니다.
package ktds.erp.admin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import ktds.erp.emp.MemberDTO;
@Repository
public class AdminDAOImpl implements AdminDAO {
@Autowired
SqlSession sqlSession;
@Override
public List<MemberDTO> getMemberList() {
return sqlSession.selectList("ktds.erp.emp.selectAll");
}
@Override
public List<MemberDTO> getCheckList(ArrayList<String> idlist) {
return null;
}
@Override
public int update(List<MemberDTO> userlist) {
return 0;
}
}
AdminService
DAO의 메소드를 호출할 Service를 작성합니다. 특이 사항은 DAO에는 메서드를 세 개 정의하였지만 Service에는 메서드를 두 개만 정의합니다. 패스워드 변경 기능에 조회하여 기능하는 두 가지 메서드가 포함되어 있습니다.
class Service{
비밀번호암호화하기(){
체크한 사원 목록 조회하기();
조회한 사원의 비밀번호 암호화하기();
}
}
class DAO{
체크한 사원 목록 조회하기(){
}
조회한 사원의 비밀번호 암호화하기(){
}
}
package ktds.erp.admin;
import java.util.List;
import ktds.erp.emp.MemberDTO;
public interface AdminService {
//전체 사원의 목록을 조회할 서비스의 메소드
List<MemberDTO> getMemberList();
//패스워드 변경할 서비스의 메소드
int passwordChange(String[] id);
}
AdminServiceImpl
전체 사원의 목록을 조회할 수 있도록 DAO의 메서드를 호출합니다.
package ktds.erp.admin;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.stereotype.Service;
import ktds.erp.emp.MemberDTO;
@Service
public class AdminServiceImpl implements AdminService {
@Autowired
AdminDAO dao;
@Autowired
private ShaPasswordEncoder passencoder;
@Override
public List<MemberDTO> getMemberList() {
return dao.getMemberList();
}
@Override
public int passwordChange(String[] id) {
return 0;
}
}
AdminController
Service의 전체 사원 조회 메서드를 호출하고 뷰와 오브젝트를 공유합니다.
package ktds.erp.admin;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import ktds.erp.emp.MemberDTO;
@Controller
public class AdminController {
@Autowired
AdminService service;
@RequestMapping("/admin/member/list.do")
public ModelAndView getMemberList() {
ArrayList<MemberDTO> memberlist = (ArrayList<MemberDTO>)service.getMemberList();
ModelAndView mav = new ModelAndView();
mav.addObject("memberlist", memberlist);
mav.setViewName("admin/memberlist");
return mav;
}
}
adminleft.jsp
전 사원의 목록을 출력할 수 있는 컨트롤러를 요청할 수 있도록 href속성을 추가합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>
<h4>관리자페이지</h4>
<h5><a href="/kimsaemERP/admin/member/list.do">비밀번호변경</a></h5>
<h5><a href="#">매출분석</a></h5>
<h5><a href="#">쇼핑몰로그분석</a></h5>
<h5><a href="#">소셜분석</a></h5>
</div>
</body>
</html>
/WEB-INF/에 admin폴더를 추가합니다.
admin-tiles.xml
admin페이지의 디자인을 추가할 수 있도록 tiles설정 파일을 추가합니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="admin/memberlist" extends="adminTemplate">
<put-attribute name="content"
value="/WEB-INF/admin/memberlist.jsp"/>
</definition>
</tiles-definitions>
memberlist.jsp
DB에서 조회한 데이터를 출력할 수 있도록 다음과 같이 JSTL을 이용하여 작업합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap Example</title>
<meta charset="UTF-8">
</head>
<body>
<h3>회원목록</h3>
<div style="padding-top: 30px">
<form action="/kimsaemERP/board/search.do">
<select name="tag">
<option value="deptno">부서</option>
<option value="name">성명</option>
<option value="group">그룹</option>
<option value="startday">입사일</option>
</select> <input type="text" name="search" /> <input type="submit" value="검색">
<input type="button" value="비밀번호변경" id="passmodify">
</form>
<br/>
<table class="table">
<thead>
<tr>
<th><input type="checkbox" id="all"/></th>
<th>아이디</th>
<th>성명</th>
<th>부서코드</th>
<th>입사일</th>
</tr>
</thead>
<tbody>
<c:forEach var="member" items="${memberlist}">
<tr>
<td><input type="checkbox" name="member" id="chk${member.id}"/></td>
<td><input type="text" value="${member.id}" name="id" disabled="disabled"/></td>
<td><a
href="/kimsaemERP/board/user/read.do?board_no=${member.name}&state=READ">${member.name}</a></td>
<%-- <td><a
href="/kimsaemERP/board/${board.category}/${board.board_no }?state=READ">${board.title}</a></td> --%>
<td>${member.deptno}</td>
<td>${member.startday}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
[step02 - 체크박스에서 선택한 사용자를 조회하기]
이제 전체 목록에서 체크한 사용자의 패스워드를 암호화할 수 있도록 처리해야 합니다. 그러나 이 기능에는 db에서 처리하는 기능이 두 가지입니다. 체크한 목록 조회하기, 조회한 사원의 모든 패스워드 데이터를 변경하기
이런 작업이 무결하게 처리될 수 있도록 하는 것이 트랜잭션 처리겠지요?
memberlist.jsp
jQuery를 이용하여 체크된 사용자의 아이디를 모두 파라미터로 전송할 수 있도록 처리합니다. <head></head> 태그 안에 <script> 태그를 추가하고 아래와 같이 jQuery코드를 추가합니다.
$("#all")에 대한 처리는 모두 선택 기능을 정의한 것이고 $("#passmodify")의 [비밀번호변경] 버튼을 클릭하면 체크박스가 선택된 모든 사용자의 아이디를 컨트롤러를 요청하며 파라미터로 넘기는 기능을 정의한 것입니다.
<script type="text/javascript">
$(document).ready(function() {
$("#all").on("click",function(){
if($('input:checkbox[id="all"]').is(":checked")==true){
$('input:checkbox[name="member"]').each(function() {
//현재 작업 중인 체크박스의 체크값을 true
this.checked = true; //checked 처리
});
}else{
$('input:checkbox[name="member"]').each(function() {
//현재 작업 중인 체크박스의 체크값을 true
this.checked = false; //checked 처리
});
}
})
$("#passmodify").on("click",function(){
paramdata=""
$('input:checkbox[name="member"]').each(function() {
if(this.checked){
//alert($(this).closest("td").next().children('input:text[name="id"]').val())
paramdata=paramdata+"id="+
$(this).closest("td").next().children('input:text[name="id"]').val()+"&"
}
})
location.href="/kimsaemERP/admin/passmodify.do?"
+paramdata.substr(0, paramdata.length-1)
})
})
</script>
AdminController
/admin/passmodify.do로 요청할 수 있도록 컨트롤러에 메서드를 추가합니다. 체크 박스가 선택된 아이디들이 여러 개 파라미터로 전송될 것이므로 id는 배열로 처리합니다.
@RequestMapping("/admin/passmodify.do")
public String modifyPassword(String[] id) {
int result = service.passwordChange(id);
if(result>=1) {
System.out.println("성공변경");
}
return "redirect:/admin/member/list.do";
}
emp.xml
체크 박스가 체크된 모든 아이디에 해당하는 데이터를 조회할 수 있도록 SQL문을 작성합니다. 체크된 아이디가 매번 다를 것이므로 동적 SQL로 작성합니다. 넘어온 아이디를 이용해서 in연산자를 완성할 것이므로 <foreach>를 이용합니다.
<select id="chkidselect" parameterType="Map" resultType="emp">
select * from member
where id in (
<foreach collection="idlist" item="id" separator=",">
#{id}
</foreach>
)
</select>
AdminDAOImpl
Service에서 전달받은 아이디가 담겨있는 ArrayList를 Map에 넣고 mapper의 sql문을 호출합니다.
@Override
public List<MemberDTO> getCheckList(ArrayList<String> idlist) {
Map<String, Object> paramMap = new HashMap<String, Object>();
System.out.println(idlist.size());
paramMap.put("idlist",idlist);
return sqlSession.selectList("ktds.erp.emp.chkidselect",paramMap);
}
AdminServiceImpl
매개변수로 넘겨받은 id배열을 ArrayList에 담고 dao의 체크된 아이디의 정보를 조회하는 메서드를 호출합니다.
@Override
public int passwordChange(String[] id) {
//1. 배열에 들어있는 모든 아이디를 ArrayList에 add하세요.
ArrayList<String> idlist = new ArrayList<String>();
for (int i = 0; i < id.length; i++) {
idlist.add(id[i]);
}
//2. id가 add된 ArrayList를 이용해서 id에 해당하는 모든 데이터를
// ArrayList<MemberDTO>의 값으로 조회할 수 있도록 dao의
// getCheckList메소드를 호출하세요.
ArrayList<MemberDTO> userlist = (ArrayList<MemberDTO>)dao.getCheckList(idlist);
System.out.println("service"+userlist.size());
}
네 개의 체크박스를 선택하고 요청하면 다음과 같이 4개가 선택되었다는 문자열이 콘솔에 출력됩니다.
[step03 - 체크박스에서 선택한 사용자의 패스워드를 암호화하기]
선택이 완료됐으므로 이제 선택된 아이디의 패스워드를 변경해야 합니다. SQL update문을 이용하여 수정합니다.
emp.xml
비밀번호를 업데이트할 수 있도록 <update> 문을 추가합니다.
<update id="passchange" parameterType="emp">
update member
set pass=#{pass}
where id=#{id}
</update>
AdminDAOImpl
emp.xml mapper의 update SQL문을 호출합니다. 조회한 모든 사원의 비밀번호를 변경해야 하므로 for문을 실행하며 for문 안에서 호출합니다.
@Override
public int update(List<MemberDTO> userlist) {
int result = 0;
for (MemberDTO user : userlist) {
sqlSession.update("ktds.erp.emp.passchange", user);
}
result = 1;
return result;
}
AdminServiceImpl
ShaPasswordEncoder는 @autowired로 주입받고 passwordChange메서드를 완성합니다. 조회해 온 사원의 정보가 담겨있는 ArrayList를 탐색하며 패스워드를 암호화하여 setPass 합니다. 이때 아이디를 salt로 추가하기 때문에 비밀번호가 동일하다고 하더라도 모두 다른 암호화 문자열이 만들어집니다.
@Service
public class AdminServiceImpl implements AdminService {
@Autowired
AdminDAO dao;
@Autowired
private ShaPasswordEncoder passencoder;
@Override
public int passwordChange(String[] id) {
//1. 배열에 들어있는 모든 아이디를 ArrayList에 add하세요.
ArrayList<String> idlist = new ArrayList<String>();
for (int i = 0; i < id.length; i++) {
idlist.add(id[i]);
}
//2. id가 add된 ArrayList를 이용해서 id에 해당하는 모든 데이터를
// ArrayList<MemberDTO>의 값으로 조회할 수 있도록 dao의
// getCheckList메소드를 호출하세요.
ArrayList<MemberDTO> userlist = (ArrayList<MemberDTO>)dao.getCheckList(idlist);
System.out.println("service"+userlist.size());
for (MemberDTO user : userlist) {
String securitypass = passencoder.encodePassword(user.getPass(), user.getId());
System.out.println(securitypass);
user.setPass(securitypass);//암호화된 패스워드를 다시 패스워드로 셋팅
}
int result = dao.update(userlist);
//3. 받아온 아이디의 password를 읽어서 암호화시킨 값을 update할 수 있도록 dao
return result;
}
admin권한을 갖고 있는 아이디로 접속한 후 관리자 페이지를 선택합니다. 비밀번호 변경을 선택하고 체크박스를 모두 선택한 후 [비밀번호변경] 버튼을 눌러 모든 패스워드가 암호화되도록 실행합니다.
SQL을 이용하여 id와 pass를 조회합니다. 모든 암호가 "1234"이지만 salt를 추가했기 때문에 암호화된 문자열이 모두 다른 것을 알 수 있습니다.
'보안 > Spring Security' 카테고리의 다른 글
인증 유무에 따라 top메뉴 다르게 보이도록 설정하기 (0) | 2019.09.15 |
---|---|
AuthenticationProvider커스트마이징하기 (0) | 2019.09.15 |
password암호화 - ShaPasswordEncoder(회원가입 수정) (0) | 2019.09.13 |
실제 DB에서 인증하기 - step04 권한 테이블을 생성하기 (0) | 2019.09.12 |
실제 DB에서 인증하기 - step03 UserDetailsService커스트마이징 (2) | 2019.09.12 |