Spring SeCurity
1. 인증 : 사용자가 자신임을 증명하는 기능
2. 인가(권한) : 권한이 있는 사용자만 사용할 수 있도록 허가하는 기능
PasswordEncoder
사용자가 사용하는 패스워드를 암호화해서 사용하는 것
만약 암호화를 하고싶지 않다면 {noop}이라는 문자열을 앞에 추가하여 이용하면 된다.
<csrf/> : 간단한 설정으로 csrf를 통해 해킹을 막을 수 있다.
SpringBootSecurityDemo
Spring Boot DevTools, Loombok, Spring Web, Thymeleaf를 dependencies에 추가해준다
HomeController.java 생성
리턴타입이 void임으로 요청한 url이 곧 html이 되는 것이다. 즉 hello.html로 자동 연결이 된다.
hello.html생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>안녕하세요. ^^</h3>
</body>
</html>
아직 Security적용전이기 떄문에 잘 들어가진다.
mavenUpdate 후 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
addStarters를 클릭하여 Spring Security를 추가해준 후 다시 localhost:8080/hello실행을 해보면
로그인창으로 바뀌며 url이 URL:http://localhost:8080/login로 바뀐것을 확인 할 수 있다.
아이디와 비밀번호를 설정을 하지 않았기 때문에 아이디는: user , 패스워드는 콘솔창에서 확인할 수 있다.
SecurityConfig.java 생성
@EnableWebSecurity
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception{
log.info("security config...");
http.authorizeRequests().antMatchers("/").permitAll();
http.authorizeRequests().antMatchers("/member/**").authenticated();
http.authorizeRequests().antMatchers("/manager/**").hasRole("MANAGER");
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN");
http.formLogin();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
log.info("build Auth global...");
auth.inMemoryAuthentication().withUser("manager")
.password("{noop}12345678").roles("MANAGER");
auth.inMemoryAuthentication().withUser("admin")
.password("{noop}12345678").roles("ADMIN");
}
}
@EnableWebSecurity라는 Annotation을 사용하며 WebSecurityConfigurerAdapter을 상속 받도록한다.
HttpSecurity는 httpResponse와 httpRequest에 관련된 보안을 담당한다.
제한은 WebSecurityConfigurerAdapter의 자식 클래스 configure overide안에서 처리를 하게된다.
{noop}을 붙였기때문에 패스워드 encording을 하지 않기위해 사용했다.
설명 | |
permitAll() | 누구나 다 허용 |
Authenticated() | 인증된 사람만 접근이 가능하도록 허용 |
hasRole() | 권한이 있는 사람만 접근이 가능하도록 허용 |
http.formLogin() | Spring Security가 가지고있는 인증창을 보여줌 |
application.properties수정
spring.thymeleaf.cache=false
logging.level.org.springframework.web=debug
logging.level.org.springframework.security=debug
thymeleaf는 계속해서 캐싱을 하기떄문에 false로 바꿔주어 새로고침시 새로 작성한 내용이 뜰 수 있도록 설정해준다.
loginPage만들기, Deniy가 발생시 이동되는 페이지 설정
http.formLogin().loginPage("/login").defaultSuccessUrl("/loginSuccess", true);
http.exceptionHandling().accessDeniedPage("/accessDenied");
http.logout().logoutUrl("/logout").invalidateHttpSession(true).logoutSuccessUrl("/login");
설명 | |
login | SecurityConfig.java에서 사용한 http.formLogin()를 http.formLogin().loginPage("/login");으로 바꿔주면 되며, login에 성공시 이동될 페이지를 설정해 주었다 |
Denied | DeniedPage를 지정하여 이동될 페이지를 만들어준다. |
logout | logout의 url을 받았을 때 세션정보를 소멸시키고 이동될 페이지를 지정하였다. |
SecurityController.java 생성
package com.example.security;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.slf4j.Slf4j;
@Controller
@Slf4j
public class SecurityController {
@GetMapping("/")
public String index() {
log.info("called Index page");
return "index"; //index.html
}
@GetMapping("/member")
public void forMember() {
log.info("called Member page");
}
// member.html
@GetMapping("/manager")
public void forManager() {
log.info("called Manager page");
}
// manager.html
@GetMapping("/admin")
public void forAdmin() {
log.info("called Admin page");
}
// admin.html
@GetMapping("/login")
public void login() {
// login.html
}
@GetMapping("/accessDenied")
public void accessDenied() {
// accessDenied.html
}
@GetMapping("/loginSuccess")
public void loginSuccess() {
// loginSuccess.html
}
@GetMapping("/logout")
public void logout() {
log.info("called Logout page");
// logout.html
}
}
기존에 컨트롤러가 있음에도 따로 만들어준 이유는 그냥 보기 편하게하기 위해서 만든 것이다.
login.html생성
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login Page</title>
</head>
<body>
<h2>Custom Login Page</h2>
<div th:if="${param.error ne null}">
<h2>Invalid Username or Password.</h2>
<h2 th:value="${param.error}"></h2>
</div>
<div th:if="${param.logout ne null}">
<h2>You have been logged out.</h2>
</div>
<form method="post">
<p>
<label for="username">Username</label> <input type="text" id="username" name="username" />
</p>
<p>
<label for="password">Password</label> <input type="password" name="password" id="password" />
</p>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<button type="submit" class="btn">Login</button>
</form>
</body>
</html>
${_csrf.parameterName}은 위조방지를 위해 hidden값으로 넣어주었다. 값이 다른request가 들어올 시 막아준다.
Spring Security에서 Username은 아이디로 간주하기 떄문에 유저의 이름을 넣어주면 안된다.
accessDenied.html생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" />
</head>
<body>
<div class="panel panel-default">
<div class="panel-body">
<div class="alert alert-danger" role="alert">
<h2>Sorry. You do not have permission to view this page.</h2>
Click Login at <a th:href="@{/login}">here</a>
</div>
</div>
</div>
</body>
</html>
권한으로 인해 들어가지 못했을 때 나오는 페이지이며 here을 클릭시 다시 로그인 페이지로 갈 수 있게 만들어 줬다.
loginSuccess.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3><span style="color:red">로그인 인증 성공</span></h3>
<h5><a th:href="@{/}">Index Page로 이동</a></h5>
<h5><a th:href="@{/member}">Member Page로 이동</a></h5>
<h5><a th:href="@{/manager}">Manager 전용 Page로 이동</a></h5>
<h5><a th:href="@{/admin}">Admin 전용 Page로 이동</a></h5>
</body>
</html>
logout.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" />
<link rel="stylesheet" th:href="@{/css/bootstrap-theme.min.css}" />
</head>
<body>
<h2>Custom Logout Page</h2>
<form method="POST">
<h3>Logout</h3>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<button type="submit" class="btn btn-primary">Logout</button>
</form>
</body>
</html>
member.html
<!DOCTYPE html>
<html xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Member page : Login 성공한 분만 보입니다.</h1>
<a th:href="@{/loginSuccess}">뒤로 가기</a>
<form action="logout" method="get">
<input type="submit" value="Logout" />
</form>
</body>
</html>
'SpringBoot 코딩' 카테고리의 다른 글
11. Thymeleaf의 sec nameSpace가 없을 때 사용하는 방법 (SpringBootSecurity Demo) (0) | 2021.12.12 |
---|---|
10. DB와 연동한 Security, Password Encording (SpringSecurity) (0) | 2021.12.11 |
8. RestFulApi를 이용한 프로젝트만들기, war packaging 진짜 Tomcat사용하기 (demo) (0) | 2021.12.09 |
7.2 Mybatis와 hikariCP를 이용한 프로젝트 만들기(BootJdbcDemo) (0) | 2021.11.26 |
6. Database(NCloud)를 이용한 SpringBoot (BootJdbcDemo) (0) | 2021.11.24 |