์์ด๋ ์ ์ฅ
์ด์ ํ์ด์ง
์ด์ ํ์ด์ง ๋ด์ฉ์ ์ด์ด์ ์งํํฉ๋๋ค.
Code
Preview
1.
๋ก๊ทธ์ธ ํ๋ฉด
2.
๋ฉ์ธ ํ๋ฉด
์์ ํ๋ก์ธ์ค
1.
ํ๋ก์ ํธ ์์ฑ
2.
ํ๋ก์ ํธ ์ค์
3.
์คํ๋ง ์ํ๋ฆฌํฐ ์ค์
4.
์์ฒญ ๊ฒฝ๋ก ๋งคํ
Preview
๋ก๊ทธ์ธ ํ๋ฉด
๋ฉ์ธ ํ๋ฉด
์์ ํ๋ก์ธ์ค
1.
ํ๋ก์ ํธ ์์ฑ
2.
ํ๋ก์ ํธ ์ค์
3.
๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ ํด๋์ค ์์ฑ
a.
์์ด๋ ์ ์ฅ ์ฒดํฌ ์ฌ๋ถ ํ์ธ
i.
์์ด๋ ์ฟ ํค ์์ฑ
ii.
์์ด๋ ์ฟ ํค ์ญ์
4.
๋ก๊ทธ์ธ ์ปจํธ๋กค๋ฌ ๋ฉ์๋
a.
์์ด๋ ์ฟ ํค ๊ฐ์ ธ์ค๊ธฐ
ํ๋ก์ ํธ ์์ฑ
build.gradle
spring boot 3.x.x
spring security 6.x.x
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.3.5'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.aloha'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
Java
๋ณต์ฌ
ํ๋ก์ ํธ ์ค์
application.properties
spring.application.name=form-custom
# ๋ฐ์ดํฐ ์์ค - MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/aloha?serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true&useSSL=false&autoReconnection=true&autoReconnection=true
spring.datasource.username=aloha
spring.datasource.password=123456
# Mybatis ์ค์
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.type-aliases-package=com.aloha.security6.domain
mybatis.mapper-locations=classpath:mybatis/mapper/**/**.xml
Markdown
๋ณต์ฌ
๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ ํด๋์ค ์์ฑ
1.
์์ด๋ ์ ์ฅ ์ฒดํฌ ์ฌ๋ถ ํ์ธ
a.
์์ด๋ ์ฟ ํค ์์ฑ
b.
์์ด๋ ์ฟ ํค ์ญ์
LoginSuccessHandler.java
/**
* ๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ
*/
@Slf4j
@Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
/**
* ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ํธ์ถ๋๋ ๋ฉ์๋
* ๐ช ์์ด๋ ์ ์ฅ ์ฟ ํค ์์ฑ
* ๐ ๋ก๊ทธ์ธ ํ ์ด์ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request
, HttpServletResponse response
, Authentication authentication) throws ServletException, IOException {
log.info("๋ก๊ทธ์ธ ์ฑ๊ณต...");
// ์์ด๋ ์ ์ฅ
String rememberId = request.getParameter("remember-id"); // โ
์์ด๋ ์ ์ฅ ์ฌ๋ถ
String username = request.getParameter("id"); // ๐ฉโ๐ผ ์์ด๋
log.info("rememberId : " + rememberId);
log.info("username : " + username);
// ์์ด๋ ์ ์ฅ ์ฒดํฌ โ
if( rememberId != null && rememberId.equals("on") ) {
Cookie cookie = new Cookie("remember-id", username); // ์ฟ ํค์ ์์ด๋ ๋ฑ๋ก
cookie.setMaxAge(60 * 60 * 24 * 7); // ์ ํจ๊ธฐ๊ฐ : 7์ผ
cookie.setPath("/");
response.addCookie(cookie);
}
// ์์ด๋ ์ ์ฅ ์ฒดํฌ โ
else {
Cookie cookie = new Cookie("remember-id", username); // ์ฟ ํค์ ์์ด๋ ๋ฑ๋ก
cookie.setMaxAge(0); // ์ ํจ๊ธฐ๊ฐ : 0 (์ญ์ )
cookie.setPath("/");
response.addCookie(cookie);
}
// ์ธ์ฆ๋ ์ฌ์ฉ์ ์ ๋ณด
CustomUser customUser = (CustomUser) authentication.getPrincipal();
Users user = customUser.getUser();
log.info("์์ด๋ : " + user.getUsername());
log.info("๋น๋ฐ๋ฒํธ : " + user.getPassword());
log.info("๊ถํ : " + user.getAuthList());
super.onAuthenticationSuccess(request, response, authentication);
}
}
Java
๋ณต์ฌ
๋ก๊ทธ์ธ ์ปจํธ๋กค๋ฌ ๋ฉ์๋
1.
์์ด๋ ์ฟ ํค ๊ฐ์ ธ์ค๊ธฐ
HomeController.java
/**
* ๋ก๊ทธ์ธ ํ๋ฉด
* @return
*/
@GetMapping("/login")
public String login(@CookieValue(value="remember-id", required = false) Cookie cookie
,Model model ) {
// @CookieValue(value="์ฟ ํค์ด๋ฆ", required = ํ์์ฌ๋ถ)
// - required=true (default) : ์ฟ ํค๋ฅผ ํ์๋ก ๊ฐ์ ธ์์ ์์ผ๋ฉด ์๋ฌ
// - required=false : ์ฟ ํค ํ์ โ โก ์ฟ ํค๊ฐ ์์ผ๋ฉด null, ์๋ฌโ
log.info(":::::::::: ๋ก๊ทธ์ธ ํ์ด์ง ::::::::::");
String username = "";
boolean rememberId = false;
if( cookie != null ) {
log.info("CookieName : " + cookie.getName());
log.info("CookieValue : " + cookie.getValue());
username = cookie.getValue();
rememberId = true;
}
model.addAttribute("username", username);
model.addAttribute("rememberId", rememberId);
return "/login";
}
Java
๋ณต์ฌ
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>๋ก๊ทธ์ธ</title>
<!-- bootstrap css -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container col-12 col-md-6 col-lg-4">
<div class="px-4 py-5 mt-5 text-center">
<h1 class="display-5 fw-bold text-body-emphasis">๋ก๊ทธ์ธ</h1>
</div>
<!-- ๋ก๊ทธ์ธ ์์ญ -->
<main class="form-signin login-box w-100 m-auto">
<form action="/login" method="post">
<!-- CSRF TOKEN -->
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
<div class="form-floating">
<input type="text" class="form-control" id="username" name="id" value="" placeholder="์์ด๋"
autofocus th:value="${username}">
<label for="username">์์ด๋</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="password" name="pw" placeholder="๋น๋ฐ๋ฒํธ">
<label for="password">๋น๋ฐ๋ฒํธ</label>
</div>
<div class="form-check text-start my-3 d-flex justify-content-around">
<div class="item">
<input class="form-check-input" type="checkbox" name="remember-id" id="remember-id-check" th:checked="${rememberId}">
<label class="form-check-label" for="remember-id-check">์์ด๋ ์ ์ฅ</label>
</div>
<div class="item">
<input class="form-check-input" type="checkbox" name="auto-login" id="remember-me-check">
<label class="form-check-label" for="remember-me-check">์๋ ๋ก๊ทธ์ธ</label>
</div>
</div>
<!-- ๋ก๊ทธ์ธ ์๋ฌ -->
<th:block th:if="${param.error}">
<p class="text-center text-danger">์์ด๋ ๋๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์๋ชป ์
๋ ฅํ์ต๋๋ค.</p>
</th:block>
<!-- ๋ก๊ทธ์์ ์๋ฃ -->
<th:block th:if="${param.logout}">
<p class="text-center text-success">์ ์์ ์ผ๋ก ๋ก๊ทธ์์ ๋์์ต๋๋ค.</p>
</th:block>
<!-- ๋ฒํผ -->
<div class="d-grid gap-2">
<button class="btn btn-lg btn-primary w-100 py-2" type="submit">๋ก๊ทธ์ธ</button>
<a href="/join" class="btn btn-lg btn-success w-100 py-2">ํ์๊ฐ์
</a>
<hr>
</div>
</form>
</main>
</div>
<!-- bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
HTML
๋ณต์ฌ