스프링 시큐리티
보안 기능을 구현하는 데 사용되는 프레임 워크
스프링 시큐리티는 필터 기반으로 동작하기 때문에 스프링 MVC와 분리되어 동작된다
- 인증(Authentication) - 로그인
- 인가(Authorization) - 권한 (메뉴 접근, 버튼 접근)
제공기능
- 세션 관리
- 로그인 처리
- CSRF 토큰 처리
- 암호화 처리
- 자동 로그인
CSRF(Cross-site request forgery)
크로스 사이트 요청 위조는 웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격
환경 설정
pom.xml
<!-- 스프링 시큐리티 라이브러리 의존관계 정의 시작 -->
<!-- 스프링 시큐리티를 웹에서 동작하도록 해줌 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- 스프링 시큐리티 설정을 도와줌 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- 스프링 시큐리티 일반 기능 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- 스프링 시큐리티와 태그라이브러리를 연결해줌 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- 스프링 시큐리티 라이브러리 의존관계 정의 끝 -->
/WEB-INF/web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml <!-- 추가! -->
</param-value>
</context-param>
<!-- 스프링 시큐리티가 제공하는 서블릿 필터 클래스를 서블릿 컨테이너에 등록함 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
/WEB-INF/spring/security-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 접근 거부 클래스 객체 생성 -->
<bean id="customAccessDenied" class="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
<!-- 로그인 성공 클래스 객체 생성 -->
<bean id="customLoginSuccess" class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>
<security:http>
<security:intercept-url pattern="/board/list" access="permitAll"/>
<security:intercept-url pattern="/board/regist" access="hasRole('ROLE_MEMBER')"/>
<security:intercept-url pattern="/notice/list" access="permitAll"/>
<security:intercept-url pattern="/notice/regist" access="hasRole('ROLE_ADMIN')"/>
<!-- 폼 기반 인증 기능을 사용 -->
<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함
사용자가 정의한 class를 로그인 성공 처리자로 지정 (authentication-success-handler-ref) -->
<security:form-login login-page="/login" authentication-success-handler-ref="customLoginSuccess"/>
<!-- //// 방법 1. URI로 요청하는 방법 error-page //// -->
<!-- 접근 거부 처리자(HTTP 상태 403 - 금지됨 : 권한 없음)
로그인은 됐지만 요청URI에 대한 권한이 없다면 /accessError 요청 URI로 자동 재요청됨
-->
<!-- <security:access-denied-handler error-page="/accessError"/> -->
<!-- //// 방법 2. 등록한 사용자 정의 class를 접근 거부 처리자로 지정 ref //// -->
<security:access-denied-handler ref="customAccessDenied"/>
</security:http>
<!-- 스프링 시큐리니티 5부터 기본적으로 PasswordEncoder를 지정해야 하는데,
그 이유는 사용자 테이블(USERS)에 비밀번호를 암호화하여 저장해야 하므로..
우리는 우선 비밀번호를 암호화 처리 하지 않았으므로
암호화 하지 않는 PasswordEncoder를 직접 구현하여 지정하기로 함
noop : no option password
-->
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<!-- name 아이디, authorities 권한 -->
<security:user name="member" password="{noop}java" authorities="ROLE_MEMBER"/>
<security:user name="admin" password="{noop}java" authorities="ROLE_MEMBER, ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
예제
회원 - list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<div class="col-md-12 card">
<div class="card-header">
<h2>회원 게시판 목록</h2>
<h6>모두가 접근 가능</h6>
</div>
<div class="card-body"></div>
</div>
회원 - regist.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<div class="col-md-12 card">
<div class="card-header">
<h2>회원 게시판 등록</h2>
<h6>로그인 한 회원만 접근 가능</h6>
</div>
<div class="card-body"></div>
</div>
공지사항 - list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<div class="col-md-12 card">
<div class="card-header">
<h2>공지사항 게시판 목록</h2>
<h6>모두가 접근 가능</h6>
</div>
<div class="card-body"></div>
</div>
공지사항 - regist.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<div class="col-md-12 card">
<div class="card-header">
<h2>공지사항 게시판 등록</h2>
<h6>로그인한 관리자만 접근 가능</h6>
</div>
<div class="card-body"></div>
</div>
BoardController.java
package kr.or.ddit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@RequestMapping("/board")
@Slf4j
@Controller
public class BoardController {
@GetMapping("/list")
public String list() {
log.info("회원 게시판 -> 목록 : 모두가 접근 가능");
return "board/list";
}
@GetMapping("/regist")
public String regist(){
log.info("회원 게시판 -> 등록 : 로그인한 회원만 접근 가능");
return "board/regist";
}
}
NoticeController.java
package kr.or.ddit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.slf4j.Slf4j;
@RequestMapping("/notice")
@Slf4j
@Controller
public class NoticeController {
@GetMapping("/list")
public String list() {
return "notice/list";
}
@GetMapping("/regist")
public String regist() {
return "notice/regist";
}
}
권한 거부
권한 거부 - CommonController.java
package kr.or.ddit.security;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class CommonController {
// 로그인은 됐지만 권한이 없을 때 요청됨
@GetMapping("/accessError")
public void accessError(Authentication auth, Model model) {
log.info("accessError : "+auth);
model.addAttribute("auth", "권한이 없습니다.");
// 메소드명과 jsp파일명이 같다면 return을 생략하고 void로 처리 가능
// return "accessError";
}
}
권한 거부 페이지 - accessError.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<div class="col-md-12 card">
<div class="card-header">
<h2>${SPRING_SECURITY_403_EXCEPTION.getMessage()}</h2> <!-- Access is denied -->
<h6>${auth}</h6>
</div>
<div class="card-body"></div>
</div>
권한 거부 클래스 객체 - CustomAccessDeniedHandler.java
package kr.or.ddit.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler{
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
// 로그인은 됐으나 권한이 없는 상태
log.info("handler");
// DB작업
// 로그작업
// 메세지 작업
/*
공지사항 등록 화면(/notice/register)은
일반회원(member/java)이 접근할 수 없는 페이지이고,
관리자(admin/java)만 접근 가능하므로..
지정된 접근 거부 처리자(CustomAccessDeniedHander)에서
접근 거부 처리 페이지(/accessError)로 리다이렉트 시킴
*/
response.sendRedirect("/accessError");
}
}
로그인 폼
LoginController.java
package kr.or.ddit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class LoginController {
@GetMapping("/login")
public String loginForm() {
return "loginForm";
}
}
loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
<div style="display: flex; justify-content: center;">
<div class="login-box">
<div class="login-logo">
<a href="../../index2.html">Login</a>
</div>
<div class="card">
<div class="card-body login-card-body">
<p class="login-box-msg">Sign in to start your session</p>
<!-- 스프링 시큐리티 로그인 폼 규칙
1. 아이디 : name 속성값이 username이어야 함
2. 비밀번호 : name 속성값이 password
3. form태그의 action속성 값이 /login, method는 post
4. csrf 처리
5. submit 버튼
-->
<form action="/login" method="post">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="ID" name="username">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-user"></span>
<i class=></i>
</div>
</div>
</div>
<div class="input-group mb-3">
<input type="password" class="form-control" placeholder="Password" name="password">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-8">
<div class="icheck-primary">
<input type="checkbox" id="remember"> <label
for="remember"> Remember Me </label>
</div>
</div>
<div class="col-4">
<button type="submit" class="btn btn-primary btn-block">Sign
In</button>
</div>
</div>
<!-- csrf : Cross Site(크로스 사이트) Request(요청) Forgery(위조) -->
<sec:csrfInput/>
</form>
</div>
</div>
</div>
</div>
로그인 성공 처리
CustomLoginSuccessHandler.java
package kr.or.ddit.security;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication auth) throws ServletException, IOException {
log.info("로그인 성공");
// auth.getPrincipal() : 사용자 정보를 가져옴
// 시큐리티에서 사용자 정보는 User 클래스의 객체로 저장됨(CustomUser.java를 참고)
// 시큐리티 user로 import할 것
User customUser = (User) auth.getPrincipal();
// 사용자 아이디를 리턴
String username = customUser.getUsername();
log.info("username : "+username);
//auth.getAuthorities() -> 권한들(ROLE_MEMBER,ROLE_ADMIN)
//authority.getAuthority() : ROLE_MEMBER
List<String> roleNames = new ArrayList<String>();
auth.getAuthorities().forEach(authority->{
roleNames.add(authority.getAuthority());
});
log.info("roleNames : "+roleNames);
// if(roleNames.contains("ROLE_ADMIN")) {
// response.sendRedirect("/notice/list");
// return;
// }
// if(roleNames.contains("ROLE_MEMBER")) {
// response.sendRedirect("/board/list");
// return;
// }
super.onAuthenticationSuccess(request, response, auth);
}
}
aside.jsp
로그인 처리 넣기 sec:authorize
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary elevation-4">
<!-- Brand Logo -->
<a href="index3.html" class="brand-link">
<img src="/resources/adminlte3/dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3" style="opacity: .8">
<span class="brand-text font-weight-light">AdminLTE 3</span>
</a>
<!-- Sidebar -->
<div class="sidebar">
<!-- Sidebar user panel (optional) -->
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<!-- 스프링 시큐리티 표현식 : 인증 및 권한 정보에 따라 화면을 동적으로 구성할 수 있고, 로그인 한 사용자 정보를 보여줄 수 있음 -->
<!-- 로그인 전 -->
<sec:authorize access="isAnonymous()">
<div class="image">
<img src="/resources/images/basic.jpg" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a href="#" class="d-block">로그인을 해주세요</a>
</div>
</sec:authorize>
<!-- 로그인 전 -->
<!-- 로그인 후 -->
<sec:authorize access="isAuthenticated()">
<div class="image">
<img src="/resources/images/NpcNmlDuk11.png" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<sec:authentication property="principal" var="user"/>
<a href="#" class="d-block">${user.username}</a>
</div>
</sec:authorize>
<!-- 로그인 후 -->
</div>
<!-- SidebarSearch Form -->
<div class="form-inline">
<div class="input-group" data-widget="sidebar-search">
<input class="form-control form-control-sidebar" type="search" placeholder="Search" aria-label="Search">
<div class="input-group-append">
<button class="btn btn-sidebar">
<i class="fas fa-search fa-fw"></i>
</button>
</div>
</div>
</div>
<!-- Sidebar Menu -->
<nav class="mt-2">
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
<!-- Add icons to the links using the .nav-icon class
with font-awesome or any other icon font library -->
<li class="nav-item menu-open">
<a href="#" class="nav-link active">
<i class="nav-icon fas fa-tachometer-alt"></i>
<p>
Dashboard
<i class="right fas fa-angle-left"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/index.html" class="nav-link active">
<i class="far fa-circle nav-icon"></i>
<p>Dashboard v1</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/index2.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Dashboard v2</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/index3.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Dashboard v3</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/widgets.html" class="nav-link">
<i class="nav-icon fas fa-th"></i>
<p>
Widgets
<span class="right badge badge-danger">New</span>
</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-copy"></i>
<p>
Layout Options
<i class="fas fa-angle-left right"></i>
<span class="badge badge-info right">6</span>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/top-nav.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Top Navigation</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/top-nav-sidebar.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Top Navigation + Sidebar</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/boxed.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Boxed</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/fixed-sidebar.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Fixed Sidebar</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/fixed-sidebar-custom.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Fixed Sidebar <small>+ Custom Area</small></p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/fixed-topnav.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Fixed Navbar</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/fixed-footer.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Fixed Footer</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/layout/collapsed-sidebar.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Collapsed Sidebar</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-chart-pie"></i>
<p>
Charts
<i class="right fas fa-angle-left"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/charts/chartjs.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>ChartJS</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/charts/flot.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Flot</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/charts/inline.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Inline</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/charts/uplot.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>uPlot</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-tree"></i>
<p>
UI Elements
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/general.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>General</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/icons.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Icons</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/buttons.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Buttons</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/sliders.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Sliders</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/modals.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Modals & Alerts</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/navbar.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Navbar & Tabs</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/timeline.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Timeline</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/UI/ribbons.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Ribbons</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-edit"></i>
<p>
Forms
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/forms/general.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>General Elements</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/forms/advanced.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Advanced Elements</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/forms/editors.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Editors</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/forms/validation.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Validation</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-table"></i>
<p>
Tables
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/tables/simple.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Simple Tables</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/tables/data.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>DataTables</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/tables/jsgrid.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>jsGrid</p>
</a>
</li>
</ul>
</li>
<li class="nav-header">EXAMPLES</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/calendar.html" class="nav-link">
<i class="nav-icon far fa-calendar-alt"></i>
<p>
Calendar
<span class="badge badge-info right">2</span>
</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/gallery.html" class="nav-link">
<i class="nav-icon far fa-image"></i>
<p>
Gallery
</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/kanban.html" class="nav-link">
<i class="nav-icon fas fa-columns"></i>
<p>
Kanban Board
</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon far fa-envelope"></i>
<p>
Mailbox
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/mailbox/mailbox.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Inbox</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/mailbox/compose.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Compose</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/mailbox/read-mail.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Read</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-book"></i>
<p>
pages
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/invoice.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Invoice</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/profile.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Profile</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/e-commerce.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>E-commerce</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/projects.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Projects</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/project-add.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Project Add</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/project-edit.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Project Edit</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/project-detail.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Project Detail</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/contacts.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Contacts</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/faq.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>FAQ</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/contact-us.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Contact us</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon far fa-plus-square"></i>
<p>
Extras
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>
Login & Register v1
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/login.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Login v1</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/register.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Register v1</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/forgot-password.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Forgot Password v1</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/recover-password.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Recover Password v1</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>
Login & Register v2
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/login-v2.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Login v2</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/register-v2.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Register v2</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/forgot-password-v2.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Forgot Password v2</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/recover-password-v2.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Recover Password v2</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/lockscreen.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Lockscreen</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/legacy-user-menu.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Legacy User Menu</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/language-menu.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Language Menu</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/404.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Error 404</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/500.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Error 500</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/pace.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Pace</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/examples/blank.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Blank Page</p>
</a>
</li>
<li class="nav-item">
<a href="starter.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Starter Page</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-search"></i>
<p>
Search
<i class="fas fa-angle-left right"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="/resources/adminlte3/pages/search/simple.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Simple Search</p>
</a>
</li>
<li class="nav-item">
<a href="/resources/adminlte3/pages/search/enhanced.html" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Enhanced</p>
</a>
</li>
</ul>
</li>
<li class="nav-header">MISCELLANEOUS</li>
<li class="nav-item">
<a href="iframe.html" class="nav-link">
<i class="nav-icon fas fa-ellipsis-h"></i>
<p>Tabbed IFrame Plugin</p>
</a>
</li>
<li class="nav-item">
<a href="https://adminlte.io/docs/3.1/" class="nav-link">
<i class="nav-icon fas fa-file"></i>
<p>Documentation</p>
</a>
</li>
<li class="nav-header">MULTI LEVEL EXAMPLE</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="fas fa-circle nav-icon"></i>
<p>Level 1</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-circle"></i>
<p>
Level 1
<i class="right fas fa-angle-left"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Level 2</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>
Level 2
<i class="right fas fa-angle-left"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-dot-circle nav-icon"></i>
<p>Level 3</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-dot-circle nav-icon"></i>
<p>Level 3</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-dot-circle nav-icon"></i>
<p>Level 3</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="far fa-circle nav-icon"></i>
<p>Level 2</p>
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="fas fa-circle nav-icon"></i>
<p>Level 1</p>
</a>
</li>
<li class="nav-header">LABELS</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon far fa-circle text-danger"></i>
<p class="text">Important</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon far fa-circle text-warning"></i>
<p>Warning</p>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon far fa-circle text-info"></i>
<p>Informational</p>
</a>
</li>
</ul>
</nav>
<!-- /.sidebar-menu -->
</div>
<!-- /.sidebar -->
</aside>
'Spring' 카테고리의 다른 글
[Spring] passwordEncoder, 로그인/로그아웃/자동로그인 (0) | 2024.08.12 |
---|---|
[Spring] JDBC 이용한 인증 (0) | 2024.08.12 |
[Spring] 입력값 검증 (Validator) (0) | 2024.08.09 |
[Spring] 트랜잭션 관리 (0) | 2024.08.09 |
[Spring] 상품 상세 - 수정,삭제 (0) | 2024.08.09 |