개발환경
프로젝트 생성 및 기본 설정
application.yml 설정
Spring Security config 생성 및 설정
회원가입 form 생성
컨트롤러 생성
프론트 페이지 생성
프로젝트 구조
GitHub 링크
개발 환경 | 버전 |
---|---|
Java | 17 |
Spring Boot | 3.2.7 |
Spring Security | 6.2.5 |
Spring Data JPA | 3.2.7 |
Lombok | 1.18.30 |
빌드 관리 도구 | Gradle 8.8 |
템플릿 엔진 | Mustache |
DB | MySQL 8.0.36 |
개발 도구 | Spring Tool Suite 4.22.1 |
File > New > Spring Starter Project
application.properties -> application.yml 변경
spring:
application:
name: login
server:
servlet:
session:
timeout: 3600 #세션 유지시간 설정
encoding:
force: true #mustache UTF-8
---
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: [URL]
username: [아이디]
password: [비밀번호]
jpa:
properties:
hibernate:
format_sql: true #JPA 쿼리문 정렬된 형태로 출력
# JPA 쿼리문, binding parameter 출력
logging:
level:
org:
hibernate:
SQL: TRACE
orm:
jdbc:
bind: TRACE
SecurityConfig.java
package com.example.login.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// csrf token
http
.csrf((csrf) -> csrf.disable()); // 비활성화
// 인가
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/", "/login", "/loginProc", "/join", "/joinProc").permitAll() // 보안 검사 없이 접근을 허용
.requestMatchers("/member/**").hasAnyRole("ADMIN", "USER") // role - ADMIN, USER만 접근 허용
.requestMatchers("/admin").hasRole("ADMIN") // role - ADMIN만 접근 허용
.anyRequest().authenticated()
);
// Custom Login
http
.formLogin((form) -> form.loginPage("/login")
.usernameParameter("loginId") // 아이디 parameter 설정
.passwordParameter("loginPwd") // 비밀번호 parameter 설정
.loginProcessingUrl("/loginProc")
.permitAll()
);
// 다중 로그인
http
.sessionManagement(session -> session
.maximumSessions(1) // 다중 로그인 허용 개수
.maxSessionsPreventsLogin(true) // 새로운 로그인 차단
);
// 세션 고정 보호
http
.sessionManagement((session) -> session
.sessionFixation((sessionFixation) -> sessionFixation
.newSession() // 로그인 시 세션 신규 생성
//.changeSessionId() // 로그인 시 세션은 그대로 두고 세션 아이디만 변경
)
);
// 로그아웃
http
.logout((logout) -> logout.logoutUrl("/logout")
.logoutSuccessUrl("/")
);
return http.build();
}
/**
* BCrypt 암호화
* @return
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
MainController.java
package com.example.login.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MainController {
/**
* 메인
* @return
*/
@GetMapping("/")
public String index() {
return "index";
}
}
JoinController.java
package com.example.login.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class JoinController {
/**
* 회원가입
* @return
*/
@GetMapping("/join")
public String join() {
return "join";
}
}
index.mustache
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>메인 페이지</title>
<style>
.container {
width: 800px !important ;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12 pt-5">
<div class="card mb-4">
<h5 class="card-header text-center">메인 페이지</h5>
<div class="card-body">
<div class="col-md-12 text-center">
<a href="/join" class="btn btn-outline-primary">회원가입</a>
</div>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
join.mustache
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>회원가입</title>
<style>
.container {
width: 800px !important ;
}
</style>
</head>
<body>
<div class="container">
<form name="joinForm" method="post" action="/joinProc">
<div class="row">
<div class="col-md-12 pt-5">
<div class="card mb-4">
<h5 class="card-header text-center">회원가입</h5>
<div class="card-body">
<div class="mb-3 row">
<label for="html5-text-input" class="col-md-2 col-form-label">아이디</label>
<div class="col-md-10">
<input class="form-control" type="text" id="loginId" name="loginId" />
</div>
</div>
<div class="mb-3 row">
<label for="html5-search-input" class="col-md-2 col-form-label">비밀번호</label>
<div class="col-md-10">
<input class="form-control" id="loginPwd" name="loginPwd" type="password" />
</div>
</div>
<div class="mb-3 row">
<label for="html5-search-input" class="col-md-2 col-form-label">닉네임</label>
<div class="col-md-10">
<input class="form-control" type="text" id="nickname" name="nickname" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<button type="submit" class="btn btn-outline-danger">회원가입</button>
<a href="/" class="btn btn-outline-secondary">취소</a>
</div>
</div>
</form>
</div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Spring Security Login | |
---|---|
2024.07.04 | [Spring Security] 커스텀 로그인 기능 구현하기 (3) |
2024.07.04 | [Spring Security] 커스텀 로그인 기능 구현하기 (2) |
2024.07.04 | [Spring Security] 커스텀 로그인 기능 구현하기 (1) |