layout 의존성 추가.
parent
af707c262a
commit
a22bf73dba
19
build.gradle
19
build.gradle
|
|
@ -19,18 +19,19 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.22'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.22'
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
developmentOnly 'org.springframework.boot:spring-boot-devtools:2.5.6'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.6'
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:2.5.6'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.5.6'
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
|
implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '2.5.3'
|
||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security:2.5.6'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE'
|
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
|
||||||
// implementation 'io.jsonwebtoken:jjwt:0.9.1'
|
// implementation 'io.jsonwebtoken:jjwt:0.9.1'
|
||||||
|
|
||||||
implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.7.0'
|
implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.7.4'
|
||||||
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
|
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
|
||||||
|
|
||||||
// implementation group: 'org.webjars', name: 'bootstrap', version: '5.1.3'
|
// implementation group: 'org.webjars', name: 'bootstrap', version: '5.1.3'
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,9 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@Controller
|
@Controller
|
||||||
public class BaseController {
|
public class BaseController {
|
||||||
|
|
||||||
|
/** * 메인 페이지 이동 * @return */
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public String home(){
|
public String main() {
|
||||||
return "login";
|
return "index";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package com.dbnt.kcgfilemanager.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class MvcConfig implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
|
|
||||||
"classpath:/static/", "classpath:/public/", "classpath:/", "classpath:/resources/",
|
|
||||||
"classpath:/META-INF/resources/", "classpath:/META-INF/resources/webjars/"};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addViewControllers(ViewControllerRegistry registry){
|
|
||||||
registry.addViewController("/").setViewName("forward:/index");
|
|
||||||
|
|
||||||
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry){
|
|
||||||
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.dbnt.kcgfilemanager.config;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum Role {
|
||||||
|
ADMIN("ROLE_ADMIN"),
|
||||||
|
USER("ROLE_USER");
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.dbnt.kcgfilemanager.config;
|
||||||
|
|
||||||
|
import com.dbnt.kcgfilemanager.userInfo.service.UserInfoService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
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.builders.WebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
private final UserInfoService userInfoService;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder(){
|
||||||
|
return new Pbkdf2PasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(WebSecurity web) throws Exception {
|
||||||
|
web.ignoring().antMatchers("/css/**", "/img/**", "/js/**", "/lib/**", "/vendor/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.authorizeRequests() // 페이지 권한 설정
|
||||||
|
.antMatchers("/info").hasRole("MEMBER") // MEMBER, ADMIN만 접근 허용
|
||||||
|
.antMatchers("/admin").hasRole("ADMIN") // ADMIN만 접근 허용
|
||||||
|
.antMatchers("/**").permitAll() // 그외 모든 경로에 대해서는 권한 없이 접근 허용
|
||||||
|
// .anyRequest().authenticated() // 나머지 요청들은 권한의 종류에 상관 없이 권한이 있어야 접근 가능
|
||||||
|
.and() // 로그인 설정
|
||||||
|
.formLogin() .loginPage("/user/login") // Custom login form 사용
|
||||||
|
.failureUrl("/login-error") // 로그인 실패 시 이동
|
||||||
|
.defaultSuccessUrl("/") // 로그인 성공 시 redirect 이동
|
||||||
|
.and() // 로그아웃 설정
|
||||||
|
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) // 로그아웃 시 URL 재정의
|
||||||
|
.logoutSuccessUrl("/") // 로그아웃 성공 시 redirect 이동
|
||||||
|
.invalidateHttpSession(true) // HTTP Session 초기화
|
||||||
|
.deleteCookies("JSESSIONID") // 특정 쿠키 제거
|
||||||
|
.and() // 403 예외처리 핸들링
|
||||||
|
.exceptionHandling().accessDeniedPage("/denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(AuthenticationManagerBuilder auth) throws Exception{
|
||||||
|
auth.userDetailsService(userInfoService).passwordEncoder(passwordEncoder());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.dbnt.kcgfilemanager.config;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import nz.net.ultraq.thymeleaf.LayoutDialect;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect;
|
||||||
|
import org.thymeleaf.spring5.SpringTemplateEngine;
|
||||||
|
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
|
||||||
|
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ThymeleafViewResolverConfig {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringResourceTemplateResolver templateResolver(){
|
||||||
|
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
|
||||||
|
templateResolver.setApplicationContext(this.applicationContext);
|
||||||
|
templateResolver.setPrefix("classpath:templates/");
|
||||||
|
templateResolver.setSuffix(".html");
|
||||||
|
templateResolver.setTemplateMode("HTML5");
|
||||||
|
templateResolver.setCacheable(false);
|
||||||
|
return templateResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringTemplateEngine templateEngine() {
|
||||||
|
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
|
||||||
|
templateEngine.setTemplateResolver(templateResolver());
|
||||||
|
templateEngine.addDialect(new SpringSecurityDialect());
|
||||||
|
templateEngine.addDialect(new LayoutDialect());
|
||||||
|
return templateEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ThymeleafViewResolver viewResolver() {
|
||||||
|
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
|
||||||
|
viewResolver.setTemplateEngine(templateEngine());
|
||||||
|
viewResolver.setCharacterEncoding("UTF-8");
|
||||||
|
viewResolver.setOrder(0);
|
||||||
|
return viewResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package com.dbnt.kcgfilemanager.config;
|
|
||||||
|
|
||||||
import com.dbnt.kcgfilemanager.userInfo.service.UserInfoService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.BeanIds;
|
|
||||||
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.builders.WebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@EnableWebSecurity
|
|
||||||
@Configuration
|
|
||||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|
||||||
|
|
||||||
private final UserInfoService userInfoService;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder(){
|
|
||||||
return new Pbkdf2PasswordEncoder();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
|
||||||
auth.userDetailsService(userInfoService);
|
|
||||||
}
|
|
||||||
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
|
|
||||||
@Override
|
|
||||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
|
||||||
return super.authenticationManagerBean();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
|
||||||
http.csrf().disable().authorizeRequests().antMatchers("/authenticate")
|
|
||||||
.permitAll().anyRequest().authenticated()
|
|
||||||
.and().exceptionHandling().and().sessionManagement()
|
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package com.dbnt.kcgfilemanager.userInfo;
|
package com.dbnt.kcgfilemanager.userInfo;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.*;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
@ -13,31 +11,60 @@ import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Data
|
@Getter
|
||||||
@AllArgsConstructor
|
@Setter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "USER_INFO")
|
@Table(name = "USER_INFO")
|
||||||
public class UserInfo{
|
public class UserInfo implements UserDetails{
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
@Column(name = "USER_ID")
|
||||||
@Column(name = "user_seq", nullable = false)
|
|
||||||
private Integer userSeq;
|
|
||||||
|
|
||||||
private String userId;
|
private String userId;
|
||||||
|
@Column(name = "PASSWORD")
|
||||||
private String password;
|
private String password;
|
||||||
|
@Column(name = "NAME")
|
||||||
private String name;
|
private String name;
|
||||||
|
@Column(name = "POSITION")
|
||||||
private int position;
|
private int position;
|
||||||
|
@Column(name = "DEPARTMENT")
|
||||||
private int department;
|
private int department;
|
||||||
|
@Column(name = "USER_ROLE")
|
||||||
private String userRole;
|
private String userRole;
|
||||||
|
@Column(name = "CREATE_DATE")
|
||||||
private Date createDate;
|
private Date createDate;
|
||||||
|
|
||||||
public Integer getUserSeq() {
|
|
||||||
return userSeq;
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
Set<GrantedAuthority> roles = new HashSet<>();
|
||||||
|
for (String role : userRole.split(",")) {
|
||||||
|
roles.add(new SimpleGrantedAuthority(role));
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserSeq(Integer userSeq) {
|
@Override
|
||||||
this.userSeq = userSeq;
|
public String getUsername() {
|
||||||
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonLocked() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,26 +6,59 @@ import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Controller
|
@Controller
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class UserInfoController {
|
public class UserInfoController {
|
||||||
private final UserInfoService userInfoService;
|
private final UserInfoService userInfoService;
|
||||||
|
|
||||||
@PostMapping("/user")
|
/** * 로그인 페이지 이동 * @return */
|
||||||
public String signup(UserInfo userInfo){
|
@GetMapping("/user/login")
|
||||||
userInfoService.signup(userInfo);
|
public String goLogin() {
|
||||||
return "redirect:/login";
|
return "login/login";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/logout")
|
/** * 로그인 에러 * @param model * @return */
|
||||||
public String logoutPage(HttpServletRequest request, HttpServletResponse response){
|
@GetMapping("/login-error")
|
||||||
new SecurityContextLogoutHandler().logout(request, response, SecurityContextHolder.getContext().getAuthentication());
|
public String loginError(Model model) {
|
||||||
return "redirect:/login";
|
model.addAttribute("loginError", true);
|
||||||
|
return "/login/login";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** * 회원가입 페이지 이동 * @return */
|
||||||
|
@GetMapping("/signup")
|
||||||
|
public String goSignup() {
|
||||||
|
return "login/signup";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** * 회원가입 처리 * @param memberDto * @return */
|
||||||
|
@PostMapping("/signup")
|
||||||
|
public String signup(UserInfo userInfo) {
|
||||||
|
userInfoService.signup(userInfo);
|
||||||
|
return "redirect:/user/login";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** * 접근 거부 페이지 이동 * @return */
|
||||||
|
@GetMapping("/denied")
|
||||||
|
public String doDenied() {
|
||||||
|
return "login/denied";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** * 내 정보 페이지 이동 * @return */
|
||||||
|
@GetMapping("/info")
|
||||||
|
public String goMyInfo() {
|
||||||
|
return "login/myinfo";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** * Admin 페이지 이동 * @return */
|
||||||
|
@GetMapping("/admin")
|
||||||
|
public String goAdmin() {
|
||||||
|
return "login/admin";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,15 @@ public class UserInfoService implements UserDetailsService {
|
||||||
private final UserInfoRepository userInfoRepository;
|
private final UserInfoRepository userInfoRepository;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public int signup(UserInfo userInfo){
|
public String signup(UserInfo userInfo){
|
||||||
Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
|
Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder();
|
||||||
userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
|
userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
|
||||||
|
|
||||||
return userInfoRepository.save(userInfo).getUserSeq();
|
return userInfoRepository.save(userInfo).getUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
|
||||||
UserInfo userInfo = userInfoRepository.findByUserId(userId).orElseThrow(()->new UsernameNotFoundException(userId));
|
return userInfoRepository.findByUserId(userId).orElseThrow(() -> new UsernameNotFoundException(userId));
|
||||||
return new User(userInfo.getUserId(), userInfo.getPassword(), new ArrayList<>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
spring.jpa.show-sql=true
|
spring.jpa.show-sql=true
|
||||||
spring.jpa.generate-ddl=false
|
spring.jpa.generate-ddl=false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<footer th:fragment="footerFragment">
|
||||||
|
<div style="border: 1px solid gold">
|
||||||
|
Footer영역입니다.
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" lang="ko">
|
||||||
|
<header th:fragment="headerFragment">
|
||||||
|
<div style="border: 1px solid green">
|
||||||
|
header.html 입니다.
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<div th:fragment="leftMenuFragment">
|
||||||
|
<div style="border: 1px solid black">
|
||||||
|
menu 영역입니다.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{layout/layout}">
|
||||||
|
<div layout:fragment="content">
|
||||||
|
<h1>This is Main Page.</h1>
|
||||||
|
<hr/>
|
||||||
|
<div sec:authorize="isAuthenticated()">
|
||||||
|
<span sec:authentication="name"></span>님 환영합니다.
|
||||||
|
</div>
|
||||||
|
<!-- 익명의 사용자 -->
|
||||||
|
<a sec:authorize="isAnonymous()" th:href="@{/user/login}">로그인</a>
|
||||||
|
<a sec:authorize="isAnonymous()" th:href="@{/signup}">회원가입</a>
|
||||||
|
|
||||||
|
<!-- 인증된 사용자 -->
|
||||||
|
<a sec:authorize="isAuthenticated()" th:href="@{/logout}">로그아웃</a>
|
||||||
|
|
||||||
|
<!-- 특정 권한의 사용자 -->
|
||||||
|
<a sec:authorize="hasRole('ROLE_MEMBER')" th:href="@{/info}">내정보</a>
|
||||||
|
<a sec:authorize="hasRole('ROLE_ADMIN')" th:href="@{/admin}">어드민</a>
|
||||||
|
</div>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>해양경찰청 파일관리 시스템</title>
|
||||||
|
|
||||||
|
<!-- 공통으로 쓰이는 css파일을넣는다.-->
|
||||||
|
<!--bootstrap-->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||||
|
<!-- 컨텐츠페이지의 CSS 영역이 들어감 -->
|
||||||
|
<th:block layout:fragment="css"></th:block>
|
||||||
|
|
||||||
|
<!-- 공통으로 쓰이는 js파일을넣는다.-->
|
||||||
|
<!--bootstrap-->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
|
||||||
|
<!-- 컨텐츠페이지의 스크립트 영역이 들어감 -->
|
||||||
|
<th:block layout:fragment="script"></th:block>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<header th:replace="fragments/header :: headerFragment"></header>
|
||||||
|
<div sec:authorize="isAnonymous()">
|
||||||
|
<div layout:fragment="content"></div>
|
||||||
|
</div>
|
||||||
|
<div sec:authorize="isAuthenticated()" class="row">
|
||||||
|
<div class="col-3">
|
||||||
|
<div th:replace="fragments/leftMenu :: leftMenuFragment"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-9">
|
||||||
|
<div layout:fragment="content"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer th:replace="fragments/footer :: footerFragment"></footer>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Admin</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>This is Admin Page.</h1>
|
||||||
|
<hr />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>denied</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>This is denied Page.</h1>
|
||||||
|
<hr />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Login</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>This is Login Page.</h1>
|
||||||
|
<hr />
|
||||||
|
<!-- Security config의 loginPage("url")와 action url과 동일하게 작성-->
|
||||||
|
<form action="/user/login" method="post">
|
||||||
|
<!-- Spring Security가 적용되면 POST 방식으로 보내는 모든 데이터는 csrf 토큰 값이 필요 -->
|
||||||
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||||
|
<p th:if="${loginError}" class="error">Wrong user or password</p>
|
||||||
|
<!-- 로그인 시 아이디의 name 애트리뷰트 값은 username -->
|
||||||
|
<!-- 파라미터명을 변경하고 싶을 경우 config class formlogin()에서 .usernameParameter("") 명시 -->
|
||||||
|
<input type="text" name="username" placeholder="이메일 입력해주세요" />
|
||||||
|
<input type="password" name="password" placeholder="비밀번호" />
|
||||||
|
<button type="submit">로그인</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>MyInfo</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>This is MyInfo Page.</h1>
|
||||||
|
<hr />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Signup</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>This is Signup Page.</h1>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<form th:action="@{/signup}" method="post">
|
||||||
|
<input type="text" name="email" placeholder="이메일 입력해주세요" />
|
||||||
|
<input type="password" name="password" placeholder="비밀번호" />
|
||||||
|
<input type="radio" name="auth" value="ROLE_ADMIN,ROLE_MEMBER" /> admin
|
||||||
|
<input type="radio" name="auth" value="ROLE_MEMBER" checked="checked" />
|
||||||
|
member <br />
|
||||||
|
<button type="submit">가입하기</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue