이번에는 화면단을 thymeleaf에서 jsp로 변경하고
로그인 / 가입 / 권한에 따른 페이지 처리를 적용하는 과정에 대한 부분입니다.
이전 포스팅에서 바뀐부분만 설명하겠습니다.
기본적인 jsp구조와 security정보는 https://victorydntmd.tistory.com/328 이사이트를 참고했습니다.
1. Application structure
2. pom.xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
기존의 thymeleaf를빼고 jsp를 이용하기 위해 tomcat-embed-jasper를 추가하였습니다.
taglibs의 경우 jsp에서 권한 및 로그인여부 파악에 사용됩니다.
3. properties 추가
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
4. index.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>메인</title>
</head>
<body>
<h1>메인페이지</h1>
<hr>
<sec:authorize access="isAnonymous()"><a href="/user/loginPage">로그인</a></sec:authorize>
<sec:authorize access="isAuthenticated()"><a href="/user/logout">로그아웃</a></sec:authorize>
<sec:authorize access="isAnonymous()"><a href="/user/signup">회원가입</a></sec:authorize>
<sec:authorize access="hasAuthority('ADMIN') or hasAuthority('USER')"><a href="/user/info">내정보</a></sec:authorize><br>
<sec:authorize access="hasAuthority('USER')"><a href="/user/admin">admin</a></sec:authorize><br>
</body>
</html>
5. login.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>로그인 페이지</title>
</head>
<body>
<h1>로그인</h1>
<hr>
<form action="/login" method="post">
<%-- <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> --%>
<input type="text" name="username" placeholder="이메일 입력해주세요">
<input type="password" name="password" placeholder="비밀번호">
<button type="submit">로그인</button>
</form>
</body>
</html>
security를 사용할경우 csrf토큰을 같이 보내줘야 제대로 동작하게 됩니다.
하지만 주석처리를 한 이유는 이후에 나오는 security 설정에서 .csrf().disable(); 를 처리해주었기 때문입니다.
6. loginSuccess.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<!DOCTYPE html>
<html lang="en" xmlns:sec="" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>로그인 성공</title>
</head>
<body>
<h1>로그인 성공!!</h1>
<hr>
<p>
<sec:authorize access="isAuthenticated()">
<sec:authentication property="principal" var="user" />
<div>${user.name}님</div>
<div>${user.authorities}</div>
</sec:authorize>
</p>
<sec:authorize access="hasAuthority('ADMIN') or hasAuthority('USER')"><a href="/user/info">내정보</a></sec:authorize><br>
<sec:authorize access="hasAuthority('USER')"><a href="/user/admin">admin</a></sec:authorize><br>
<a href="/">메인으로 이동</a>
</body>
</html>
principal에 로그인한 유저 정보가 담겨있습니다.
hasAuthority를 이용하여 ADMIN권한 또는 USER권한일경우 내정보에 대한 메뉴를 화면에 출력하고
hasAuthority를 이용하여 ADMIN권한일경우 admin메뉴를 화면에 출력합니다.
7. logout.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>로그아웃</title>
</head>
<body>
<h1>로그아웃 처리되었습니다.</h1>
<hr>
<a href="/">메인으로 이동</a>
</body>
</html>
8. signup.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<title>회원가입 페이지</title>
</head>
<body>
<h1>회원 가입</h1>
<hr>
<form action="/user/signup" method="post">
<input type="text" name="username" placeholder="이메일 입력해주세요">
<input type="password" name="password" placeholder="비밀번호">
<input type="text" name="name" placeholder="이름">
<input type="hidden" name="isAccountNonExpired" value="true">
<input type="hidden" name="isAccountNonLocked" value="true">
<input type="hidden" name="isCredentialsNonExpired" value="true">
<input type="hidden" name="isEnabled" value="true">
<button type="submit">가입하기</button>
</form>
</body>
</html>
9. myinfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>내정보</title>
</head>
<body>
<h1>내정보 확인 페이지입니다.</h1>
<hr>
</body>
</html>
10. admin.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>어드민</title>
</head>
<body>
<h1>어드민 페이지입니다.</h1>
<hr>
</body>
</html>
11. denied.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>접근 거부</title>
</head>
<body>
<h1>접근 불가 페이지입니다.</h1>
<hr>
</body>
</html>
12. SecurityConfig 수정
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.security_blog.yg1110.servicer.UserService;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user/admin/**").access("hasAuthority('ADMIN')")
.antMatchers("/user/myinfo").access("hasAuthority('USER')") // 페이지 권한 설정
.antMatchers("/", "/user/signup", "/user/denied", "/user/logout/result").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/user/loginPage")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/user/login/result")
.permitAll() // 로그인 설정
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/user/logout")) // 로그아웃 설정
.logoutSuccessUrl("/user/logout/result").invalidateHttpSession(true)
.and()
.exceptionHandling().accessDeniedPage("/user/denied") // 403 예외처리 핸들링
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(userService.passwordEncoder());
}
}
.antMathchers("/user/admin/**").access("hasAuthority('ADMIN')") | 해당 경로는 ADMIN권한만 연결이 가능합니다. |
.antMathchers("/user/myinfo/**").access("hasAuthority('USER')") | 해당 경로는 USER권한만 연결이가능합니다. |
.antMatchers("/", "/user/signup", "/user/denied", "/user/logout/result").permitAll() | 해당 경로는 모두 연결이 가능합니다. |
.anyRequest().authenticated() | 나머지 경로는 권한을부여받아야지만(로그인) 연결이 가능합니다. |
.formLogin().loginPage("/user/loginPage") | 해당 경로의 커스텀된 로그인 페이지를 출력합니다. |
.loginProcessingUrl("/login") | 로그인버튼을 클릭했을시 action의 경로입니다.(기본적으로 post) |
.defaultSuccessUrl("/user/login/result") | 로그인이 성공했을경우 해당경로의 화면을 출력합니다. |
.logout().logoutRequstMatcher(new AntPathRequestMatcher("/user/logout")) | 해당경로로 요청이 왔을경우 로그아웃이 진행됩니다. |
.logoutSuccessUrl("/user/logout/result").invalidateHttpSession(true) | 로그아웃 성공시 출력되는 경로입니다. |
.exceptionHandling().accessDeniedPage("/user/denied") | 권한이 없을 경우 해당 경로의 페이지가 출력됩니다. |
.csrf().disable() | 요청을 받을때 csrf토큰이 없어도 호출됩니다. |
13. Usercontroller 수정
package com.security_blog.yg1110.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.security_blog.yg1110.domain.User;
import com.security_blog.yg1110.mapper.UserMapper;
import com.security_blog.yg1110.servicer.UserServiceImpl;
@Controller
public class UserController {
@Autowired UserMapper userMapper;
@Autowired UserServiceImpl userservice;
// 메인 페이지
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index() {
return "index";
}
// 회원가입 페이지
@GetMapping("/user/signup")
public String dispSignup() {
return "signup";
}
// 회원가입 처리
@PostMapping("/user/signup")
public String execSignup(User user) {
System.out.println(user);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
// authorities.add(new SimpleGrantedAuthority("ADMIN"));
authorities.add(new SimpleGrantedAuthority("USER"));
user.setAuthorities(authorities);
userservice.createUser(user);
return "redirect:/user/login";
}
// 로그인 페이지
@GetMapping("/user/loginPage")
public String dispLogin() {
return "login";
}
// 로그인 결과 페이지
@GetMapping("/user/login/result")
public String dispLoginResult() {
return "loginSuccess";
}
// 로그아웃 결과 페이지
@GetMapping("/user/logout/result")
public String dispLogout() {
return "logout";
}
// 접근 거부 페이지
@GetMapping("/user/denied")
public String dispDenied() {
return "denied";
}
// 내 정보 페이지
@GetMapping("/user/info")
public String dispMyInfo() {
return "myinfo";
}
// 어드민 페이지
@GetMapping("/user/admin")
public String dispAdmin() {
return "admin";
}
}
회원가입시 무조건 USER권한을 따로 리스트에 넣어서 주고 있는데 이부분에 대해서 추후에 수정예정입니다.
'Springboot' 카테고리의 다른 글
Springboot security (6) - Oauth2.0 (Google, facebook) 적용 (0) | 2020.03.07 |
---|---|
Springboot security (5) - jwt 적용 (0) | 2020.03.03 |
Springboot security (4) - Oauth2.0 (google) 적용 (0) | 2020.02.28 |
Springboot security (2) - mysql 연동 (0) | 2020.02.26 |
Springboot security (1) - 기본적인 인증과정 (0) | 2020.02.23 |