스프링 MVC

준비중..

스프링 MVC

스프링을 사용한 웹서비스 만들기

18 권한 부여하기

# 권한 부여하기 --- ## 권리자 권한 부여 먼저 관리자 계정을 만들어 줍니다. SQL 쿼리문을 통해 직접 입력 해주세요. ```sql INSERT INTO authorities (email, authority) VALUES ('[email protected]', 'ROLE_ADMIN') ``` 권한 부여 후 테이블 조회 결과는 아래와 같습니다.  ![Imgur](http://i.imgur.com/18m49Wc.png) ## 관리자 페이지 버튼 등록 해더에 관리 버튼을 만들어 줍시다. ![Imgur](http://i.imgur.com/96cPtvC.png) 아래는 관리 버튼을 추가한 소스코드입니다. 기존 도서 버튼 다음에 관리자 추가해 주시면 됩니다. **tiles/components/header.jsp** ```jsp ... <ul class="nav navbar-nav navbar-left"> <li><a href="<c:url value='/books'/>">도서</a></li> <!-- 관리자 페이지 버튼 --> <sec:authorize access="hasRole('ADMIN')"> <li class="nav-item"><a class="nav-link" href="<c:url value='/admins'/>">관리</a></li> </sec:authorize> </ul> ... ``` ## 관리자 페이지 생성 그럼 관리자 페이지를 만들어 줍시다. **views/admins/index.jsp** ``` <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/security/tags" prefix="s"%> <%@ page pageEncoding="utf-8" %> <div class="jumbotron"> <h1>관리자 페이지</h1> <p>views/admins/index.jsp</p> </div> ``` 컨트롤러를 만들어 줍니다. ![Imgur](http://i.imgur.com/F9sUUvq.png) **AdminsController.java** ``` @Controller public class AdminsController { @RequestMapping(value = "/admins", method = RequestMethod.GET) public String index() { return "admins/index"; } } ``` 버튼 클릭시 페이지를 볼 수 있게 되었습니다. 클릭하면 아래와 같은 페이지를 볼 수 있습니다. ![Imgur](http://i.imgur.com/zNM136Y.png) ## 사용자 목록 생성 관리자 페이지에 사용자 목록 만들어 줍시다. 반복문을 통해 사용자를 출력해주세요. **views/admins/index.jsp** ```jsp ... <div class="container"> <table class="table table-striped"> <thead> <tr> <th>User</th> <th>Roles</th> </tr> </thead> <tbody> <c:forEach var="user" items="${ users }"> <tr> <td>${ user.email }</td> <td> <c:forEach var="authority" items="${ user.authorities }">${ authority.authority }</c:forEach> </td> </tr> </c:forEach> </tbody> </table> </div> ... ``` 컨트롤러에서 사용자리스트를 모델에 등록하지 않았으므로 아직 데이터가 보여지지 않습니다. ![Imgur](http://i.imgur.com/QREvAZO.png) ## 사용자 데이터 가져오기 이제 컨트롤러에서 사용자들의 데이터를 가져와야 합니다. **AdminsController.java** ``` @Controller public class AdminsController { @Autowired private UserMapper userMapper; @RequestMapping(value = "/admin", method = RequestMethod.GET) public String index(Model model) { List<User> users = userMapper.selectUsers(); model.addAttribute("users", users); return "admins/index"; } } ``` 유저 맵퍼에 selectUsers() 메소드를 만들어줘야 동작을 하겠지요? **UserMapper.java** ``` ... @Select("SELECT id, email FROM users") @Results(value = { @Result(property = "id", column = "id"), @Result(property = "email", column = "email"), @Result(property = "authorities", column = "email", javaType = List.class, many = @Many(select = "selectAuthority")) }) public List<User> selectUsers(); @Select("SELECT email, authority " + "FROM authorities " + "WHERE email = #{email}") public List<Authority> selectAuthority(String email); ... ``` 위 메소드는 유저 테이블 뿐만 아니라 해당 각 유저의 권한들도 가져오는 코드입니다. 해당 메소드의 정상 동작을 위해서 `User` 클래스를 아래와 같이 변경해 줍니다. **User.java** ``` public class User { int id; // @Email String email; // @Size(min = 4, max = 20) String password; List<Authority> authorities; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<Authority> getAuthorities() { return authorities; } public void setAuthorities(List<Authority> authorities) { this.authorities = authorities; } @Override public String toString() { return "User [id=" + id + ", email=" + email + ", password=" + password + ", authorities=" + authorities + "]"; } } ``` 위 코드를 보면 `User` 클래스가 Authority 클래스의 리스트를 필드로 가지고 있습니다. Authority 클래스를 생성해야겠지요? **Authority.java** ``` public class Authority { String email; String authority; public boolean isRole(String role) { return authority.equals("ROLE_" + role.toUpperCase()); } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } @Override public String toString() { return "Role [email=" + email + ", authority=" + authority + "]"; } } ``` 자 이제 관리자 페이지를 확인해봅시다! ![Imgur](http://i.imgur.com/U9B7CbM.png) ## 권한 부여 및 삭제 권한 부여 및 삭제 버튼을 추가해줍니다. **views/admins/index.jsp** ```jsp ... <div class="container"> <table class="table table-striped"> <thead> <tr> <th>User</th> <th>Roles</th> <th></th> </tr> </thead> <tbody> <c:forEach var="user" items="${ users }"> <tr> <td>${ user.email }</td> <td><c:forEach var="authority" items="${ user.authorities }"> ${ authority.authority }, </c:forEach> </td> <td><c:url var="changeRoleUrl" value="/admins/role/${ user.id }" /> <a href="${ changeRoleUrl }/admin" class="btn btn-light">관리자</a> <a href="${ changeRoleUrl }/manager" class="btn btn-light">매니저</a> <a href="${ changeRoleUrl }/user" class="btn btn-light">사용자</a> </td> </tr> </c:forEach> </tbody> </table> </div> ... ``` 아래와 같은 화면이 나타납니다. ![Imgur](http://i.imgur.com/zV8AVOR.png) ## 권한 부여 기능 버튼을 클릭하여 권한을 부여 또는 삭제 할 수 있게 해줍시다. 버튼 클릭 시 전송되는 요청을 받을 수 있게 컨트롤러에 메소드를 추가해 줍니다. **AdminsController.java** ```java @Controller public class AdminsController { @Autowired private UserMapper userMapper; @RequestMapping(value = "/admin", method = RequestMethod.GET) public String index(Model model) { List<User> users = userMapper.selectUsers(); model.addAttribute("users", users); return "admins/index"; } @RequestMapping(value = "/admin/role/{userId}/{role}") public String changeRole(@PathVariable int userId, @PathVariable String role) { toggleRole(userId, role); return "redirect:/admin"; } } ``` toggleRole() 메소드를 추가해 줍니다. **AdminsController.java** ```java @Controller public class AdminsController { @Autowired private UserMapper userMapper; @RequestMapping(value = "/admin", method = RequestMethod.GET) public String index(Model model) { List<User> users = userMapper.selectUsers(); model.addAttribute("users", users); return "admins/index"; } @RequestMapping(value = "/admin/role/{userId}/{role}") public String changeRole(@PathVariable int userId, @PathVariable String role) { toggleRole(userId, role); return "redirect:/admin"; } private void toggleRole(int userId, String role) { User user = userMapper.selectUserById(userId); if (! user.hasRole(role)) userMapper.insertAuthority(user.getEmail(), "ROLE_" + role.toUpperCase()); else userMapper.deleteAuthority(user.getEmail(), "ROLE_" + role.toUpperCase()); } } ``` 마지막으로 `UserMapper` 인터페이스에 아래의 메소드를 추가해줍니다. + selectUserById(int); + insertAuthority(String, String); + deleteAuthority(String, String); **UserMapper.java** ```java ... @Select("SELECT id, email FROM users WHERE id = #{userId}") @Results(value = { @Result(property = "id", column = "id"), @Result(property = "email", column = "email"), @Result(property = "authorities", column = "email", javaType = List.class, many = @Many(select = "selectAuthority")) }) public User selectUserById(int userId); @Insert("INSERT INTO authorities (email, authority) " + "VALUES (#{email}, #{authority})") public boolean insertAuthority(@Param("email") String email, @Param("authority") String authority); @Delete("DELETE FROM authorities WHERE email = #{email} AND authority = #{role}") public void deleteAuthority(@Param("email") String email, @Param("role") String role); ... ``` 이제 버튼을 클릭하면 권한이 부여/삭제가 됩니다. ## 권한에 따른 버튼색 달리하기 좀더 직관적인 UI를 만들어 봅시다. 해당 권한이 있는 경우, 버튼색을 파랗게 해주고 없는경우는 회색으로 만들어 볼까요? **views/admins/index.jsp** ```jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/security/tags" prefix="s"%> <%@ page pageEncoding="utf-8"%> <div class="jumbotron"> <h1>관리자 페이지</h1> <p>views/admins/index.jsp</p> </div> <div class="container"> <table class="table table-striped"> <thead> <tr> <th>User</th> <th>Roles</th> <th></th> </tr> </thead> <tbody> <c:forEach var="user" items="${ users }"> <tr> <td>${ user.email }</td> <td><c:forEach var="authority" items="${ user.authorities }"> ${ authority.authority }, </c:forEach> </td> <td><c:url var="changeRoleUrl" value="/admins/role/${ user.id }" /> <a href="${ changeRoleUrl }/admin" class="btn <c:if test="${ user.hasRole('ADMIN') }">btn-primary</c:if>">관리자</a> <a href="${ changeRoleUrl }/manager" class="btn <c:if test="${ user.hasRole('MANAGER') }">btn-primary</c:if>">매니저</a> <a href="${ changeRoleUrl }/user" class="btn <c:if test="${ user.hasRole('USER') }">btn-primary</c:if>">사용자</a> </td> </tr> </c:forEach> </tbody> </table> </div> ``` Line 30~32를 보면, 해당 권한에 따른 버튼색을 달리하는 코드가 추가 됨을 알 수 있습니다. 하지만 아직 제대로 동자 하지 안습니다. 왜냐하면 `hasRole` 메소드가 구현되지 않았기 때문입니다. 정상 동작을 위해 `User` 클래스에 hasRole(String) 메소드를 구현해줍니다. **User.java** ```java public class User { int id; // @Email String email; // @Size(min = 4, max = 20) String password; List<Authority> authorities; public boolean hasRole(String role) { for (Authority auth : authorities) if (auth.isRole(role)) return true; return false; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<Authority> getAuthorities() { return authorities; } public void setAuthorities(List<Authority> authorities) { this.authorities = authorities; } @Override public String toString() { return "User [id=" + id + ", email=" + email + ", password=" + password + ", authorities=" + authorities + "]"; } } ``` 위 코드가 동작하기 위해서는 `Authority` 클래스에도 isRole(String) 메소드를 만들어 줘야합니다. **Authority.java** ```java public class Authority { String email; String authority; public boolean isRole(String role) { return authority.equals("ROLE_" + role.toUpperCase()); } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } @Override public String toString() { return "Role [email=" + email + ", authority=" + authority + "]"; } } ``` 모든 준비가 끝났습니다. 관리자 페이지를 확인해봅시다. ![Imgur](http://i.imgur.com/CQW0p32.png)