Compare commits
19 Commits
default_co
...
custom-fil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f13595479 | ||
|
|
26ef372734 | ||
|
|
a3c9c60d9e | ||
|
|
4c0c60a69f | ||
|
|
432e0aff08 | ||
|
|
b209a017d4 | ||
|
|
d798b23d63 | ||
|
|
8c26d488fc | ||
|
|
f6d702da7f | ||
|
|
b7d58486ac | ||
|
|
3f5f5cbc4b | ||
|
|
110324776d | ||
|
|
584d7f1b94 | ||
|
|
20ccbd7e13 | ||
|
|
ad10828483 | ||
|
|
de564ef4fe | ||
|
|
b5c06cf76f | ||
|
|
d4f032ad32 | ||
|
|
b531d2ac0e |
14
build.gradle
14
build.gradle
@@ -19,17 +19,27 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// spring data jpa
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
// security
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
// 웹 페이지를 쉽게 생성하기 위한 thymeleaf
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
// spring web mvc
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
// Thymeleaf에서 SpringSecurity를 Integration
|
||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
|
||||
// lombok
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
// developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
// developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
// h2
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
// starter test
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
// security test
|
||||
testImplementation 'org.springframework.security:spring-security-test'
|
||||
// junit test
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ package com.example.springsecuritystudy;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
|
||||
/**
|
||||
* SpringSecurity 학습용 Application
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SpringSecurityStudyApplication {
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.example.springsecuritystudy.admin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import com.example.springsecuritystudy.note.Note;
|
||||
import com.example.springsecuritystudy.note.NoteService;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/admin")
|
||||
public class AdminController {
|
||||
|
||||
private final NoteService noteService;
|
||||
|
||||
/**
|
||||
* 어드민인 경우 게시글 조회
|
||||
* @return admin/index.html
|
||||
*/
|
||||
@GetMapping
|
||||
public String getPostForAdmin(Authentication authentication, Model model) {
|
||||
User user = (User) authentication.getPrincipal();
|
||||
List<Note> notes = noteService.findByUser(user);
|
||||
model.addAttribute("notes", notes);
|
||||
return "admin/index";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.springsecuritystudy.common;
|
||||
|
||||
/**
|
||||
* 이미 등록된 유저를 재등록하려고 할때 발생하는 Exception
|
||||
*/
|
||||
public class AlreadyRegisteredUserException extends RuntimeException {
|
||||
|
||||
public AlreadyRegisteredUserException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AlreadyRegisteredUserException() {
|
||||
super("이미 등록된 유저입니다.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.springsecuritystudy.common;
|
||||
|
||||
/**
|
||||
* 유저를 찾을 수 없을 때 발생하는 Exception
|
||||
*/
|
||||
public class UserNotFoundException extends RuntimeException {
|
||||
|
||||
public UserNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UserNotFoundException() {
|
||||
super("유저를 찾을 수 없습니다.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.example.springsecuritystudy.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
import com.example.springsecuritystudy.note.NoteService;
|
||||
import com.example.springsecuritystudy.notice.NoticeService;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
import com.example.springsecuritystudy.user.UserService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 초기 상태 등록 Config
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@Profile(value = "!test")
|
||||
public class InitializeDefaultConfig {
|
||||
|
||||
private final UserService userService;
|
||||
private final NoteService noteService;
|
||||
private final NoticeService noticeService;
|
||||
|
||||
/**
|
||||
* 유저등록, note 4개 등록
|
||||
*/
|
||||
@Bean
|
||||
public void initializeDefaultUser() {
|
||||
User user = userService.signup("user", "user");
|
||||
noteService.saveNote(user, "테스트", "테스트입니다.");
|
||||
noteService.saveNote(user, "테스트2", "테스트2입니다.");
|
||||
noteService.saveNote(user, "테스트3", "테스트3입니다.");
|
||||
noteService.saveNote(user, "여름 여행계획", "여름 여행계획 작성중...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 어드민등록, 공지사항 2개 등록
|
||||
*/
|
||||
@Bean
|
||||
public void initializeDefaultAdmin() {
|
||||
userService.signupAdmin("admin", "admin");
|
||||
noticeService.saveNotice("환영합니다", "환영합니다 여러분");
|
||||
noticeService.saveNotice("게시글 작성 방법 공지", "1. 회원가입\n2. 로그인\n3. 게시글 작성\n4. 저장\n* 본인 외에는 게시글을 볼 수 없습니다.");
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@ package com.example.springsecuritystudy.config;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
/**
|
||||
* JPA auditor enable
|
||||
*/
|
||||
@Configuration
|
||||
@EnableJpaAuditing
|
||||
public class AuditorConfig {
|
||||
public class JpaAuditorConfig {
|
||||
}
|
||||
@@ -3,18 +3,12 @@ package com.example.springsecuritystudy.config;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.filter.HiddenHttpMethodFilter;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* WebMVC Config
|
||||
*/
|
||||
@Configuration
|
||||
public class MvcConfig implements WebMvcConfigurer {
|
||||
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("index");
|
||||
registry.addViewController("/home").setViewName("index");
|
||||
registry.addViewController("/admin").setViewName("admin/index");
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
}
|
||||
public class MvcConfig {
|
||||
|
||||
@Bean
|
||||
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
|
||||
|
||||
@@ -5,6 +5,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* PasswordEncoder Config
|
||||
*/
|
||||
@Configuration
|
||||
public class PasswordEncoderConfig {
|
||||
|
||||
|
||||
@@ -1,32 +1,55 @@
|
||||
package com.example.springsecuritystudy.config;
|
||||
|
||||
import com.example.springsecuritystudy.filter.StopwatchFilter;
|
||||
import com.example.springsecuritystudy.filter.TesterAuthenticationFilter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
import com.example.springsecuritystudy.user.UserRepository;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@EnableWebSecurity
|
||||
/**
|
||||
* Security 설정 Config
|
||||
*/
|
||||
@EnableWebSecurity(debug = true)
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// stopwatch filter
|
||||
http.addFilterBefore(
|
||||
new StopwatchFilter(),
|
||||
WebAsyncManagerIntegrationFilter.class
|
||||
);
|
||||
// tester authentication filter
|
||||
http.addFilterBefore(
|
||||
new TesterAuthenticationFilter(authenticationManager(http.getSharedObject(AuthenticationConfiguration.class))),
|
||||
UsernamePasswordAuthenticationFilter.class
|
||||
);
|
||||
http
|
||||
.httpBasic().disable()
|
||||
.csrf();
|
||||
http
|
||||
.rememberMe();
|
||||
http
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.antMatchers("/", "/home", "/signup", "/example",
|
||||
"/css/**", "/js/**", "/h2-console/**").permitAll()
|
||||
.antMatchers("/post").hasRole("USER")
|
||||
.antMatchers("/", "/home", "/signup").permitAll()
|
||||
.antMatchers("/note").hasRole("USER")
|
||||
.antMatchers("/admin").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.POST, "/notice").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE, "/notice").hasRole("ADMIN")
|
||||
@@ -50,12 +73,11 @@ public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
return web -> web.ignoring().antMatchers("/css/**", "/js/**", "/h2-console/**");
|
||||
// 정적 리소스 spring security 대상에서 제외
|
||||
return (web) -> web.ignoring()
|
||||
.antMatchers("/h2-console/**")
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations())
|
||||
;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
return username -> userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("유저를 찾지 못 했습니다."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.example.springsecuritystudy.config;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.example.springsecuritystudy.common.UserNotFoundException;
|
||||
import com.example.springsecuritystudy.user.UserRepository;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class UserDetailServiceImpl implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
return userRepository.findByUsername(username)
|
||||
.orElseThrow(UserNotFoundException::new);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.example.springsecuritystudy.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class SampleController {
|
||||
|
||||
@GetMapping("/example")
|
||||
public String example(Model model) {
|
||||
model.addAttribute("name", "정우성");
|
||||
model.addAttribute("age", 51);
|
||||
return "example";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.springsecuritystudy.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class StopwatchFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
StopWatch stopWatch = new StopWatch(request.getServletPath());
|
||||
stopWatch.start();
|
||||
filterChain.doFilter(request, response);
|
||||
stopWatch.stop();
|
||||
// Log StopWatch '/login' : running time = 150545041 ns
|
||||
log.info(stopWatch.shortSummary());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.example.springsecuritystudy.filter;
|
||||
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 테스트 유저인 경우에는 어드민과 유저 권한 모두를 줍니다.
|
||||
*/
|
||||
public class TesterAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
|
||||
public TesterAuthenticationFilter(AuthenticationManager authenticationManager) {
|
||||
super(authenticationManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws
|
||||
AuthenticationException {
|
||||
Authentication authentication = super.attemptAuthentication(request, response);
|
||||
User user = (User) authentication.getPrincipal();
|
||||
if (user.getUsername().startsWith("test")) {
|
||||
// 테스트 유저인 경우 어드민과 유저 권한 모두 부여
|
||||
return new UsernamePasswordAuthenticationToken(
|
||||
user,
|
||||
null,
|
||||
Stream.of("ROLE_ADMIN", "ROLE_USER")
|
||||
.map(authority -> (GrantedAuthority) () -> authority)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.example.springsecuritystudy.post;
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
@@ -15,6 +13,7 @@ import com.example.springsecuritystudy.model.BaseTimeEntity;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -22,7 +21,7 @@ import lombok.NoArgsConstructor;
|
||||
@Table
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class Post extends BaseTimeEntity {
|
||||
public class Note extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@@ -30,17 +29,20 @@ public class Post extends BaseTimeEntity {
|
||||
private String title;
|
||||
@Lob
|
||||
private String content;
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PostStatus status;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "USER_ID")
|
||||
private User user;
|
||||
|
||||
public Post(String title, String content, User user) {
|
||||
@Builder
|
||||
public Note(String title, String content, User user) {
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.status = PostStatus.Y;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public void updatePost(String title, String content) {
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.springsecuritystudy.post;
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,30 +18,30 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/post")
|
||||
public class PostController {
|
||||
@RequestMapping("/note")
|
||||
public class NoteController {
|
||||
|
||||
private final PostService postService;
|
||||
private final NoteService noteService;
|
||||
|
||||
@GetMapping
|
||||
public String findByPost(Authentication authentication, Model model) {
|
||||
public String getPost(Authentication authentication, Model model) {
|
||||
User user = (User) authentication.getPrincipal();
|
||||
List<Post> posts = postService.findByUser(user);
|
||||
model.addAttribute("posts", posts);
|
||||
return "post/index";
|
||||
List<Note> notes = noteService.findByUser(user);
|
||||
model.addAttribute("notes", notes);
|
||||
return "note/index";
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String savePost(@ModelAttribute PostDto postDto, Authentication authentication) {
|
||||
public String savePost(@ModelAttribute NoteDto noteDto, Authentication authentication) {
|
||||
User user = (User) authentication.getPrincipal();
|
||||
postService.savePost(user, postDto.getTitle(), postDto.getContent());
|
||||
return "redirect:post";
|
||||
noteService.saveNote(user, noteDto.getTitle(), noteDto.getContent());
|
||||
return "redirect:note";
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public String deletePost(@RequestParam Long id, Authentication authentication) {
|
||||
User user = (User) authentication.getPrincipal();
|
||||
postService.deletePost(user, id);
|
||||
return "redirect:post";
|
||||
noteService.deleteNote(user, id);
|
||||
return "redirect:note";
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.example.springsecuritystudy.post;
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PostDto {
|
||||
public class NoteDto {
|
||||
|
||||
private String title;
|
||||
private String content;
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
|
||||
public interface NoteRepository extends JpaRepository<Note, Long> {
|
||||
|
||||
List<Note> findByUserOrderByIdDesc(User user);
|
||||
|
||||
Note findByIdAndUser(Long id, User user);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.example.springsecuritystudy.common.UserNotFoundException;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
public class NoteService {
|
||||
|
||||
private final NoteRepository noteRepository;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Note> findByUser(User user) {
|
||||
userNullCheck(user);
|
||||
if (Boolean.TRUE.equals(user.isAdmin())) {
|
||||
return noteRepository.findAll(Sort.by(Sort.Direction.DESC, "id"));
|
||||
}
|
||||
return noteRepository.findByUserOrderByIdDesc(user);
|
||||
}
|
||||
|
||||
private static void userNullCheck(User user) {
|
||||
if (user == null) {
|
||||
throw new UserNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public Note saveNote(User user, String title, String content) {
|
||||
userNullCheck(user);
|
||||
return noteRepository.save(new Note(title, content, user));
|
||||
}
|
||||
|
||||
public void deleteNote(User user, Long id) {
|
||||
userNullCheck(user);
|
||||
Note note = noteRepository.findByIdAndUser(id, user);
|
||||
noteRepository.delete(note);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package com.example.springsecuritystudy.notice;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
|
||||
import com.example.springsecuritystudy.model.BaseTimeEntity;
|
||||
import com.example.springsecuritystudy.post.PostStatus;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -25,12 +23,10 @@ public class Notice extends BaseTimeEntity {
|
||||
private String title;
|
||||
@Lob
|
||||
private String content;
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PostStatus status;
|
||||
|
||||
@Builder
|
||||
public Notice(String title, String content) {
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.status = PostStatus.Y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,13 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.example.springsecuritystudy.post.PostDto;
|
||||
import com.example.springsecuritystudy.note.NoteDto;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 공지사항 서비스 Controller
|
||||
*/
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/notice")
|
||||
@@ -30,8 +33,8 @@ public class NoticeController {
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String savePost(@ModelAttribute PostDto postDto) {
|
||||
noticeService.saveNotice(postDto.getTitle(), postDto.getContent());
|
||||
public String savePost(@ModelAttribute NoteDto noteDto) {
|
||||
noticeService.saveNotice(noteDto.getTitle(), noteDto.getContent());
|
||||
return "redirect:notice";
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.example.springsecuritystudy.notice;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -16,7 +17,7 @@ public class NoticeService {
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Notice> findAll() {
|
||||
return noticeRepository.findAll();
|
||||
return noticeRepository.findAll(Sort.by(Sort.Direction.DESC, "id"));
|
||||
}
|
||||
|
||||
public Notice saveNotice(String title, String content) {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.example.springsecuritystudy.post;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
|
||||
List<Post> findByUserAndStatus(User user, PostStatus status);
|
||||
|
||||
Post findByIdAndUser(Long id, User user);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.example.springsecuritystudy.post;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
import com.example.springsecuritystudy.user.UserRepository;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
public class PostService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final PostRepository postRepository;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Post> findByUser(User user) {
|
||||
userNullCheck(user);
|
||||
return postRepository.findByUserAndStatus(user, PostStatus.Y);
|
||||
}
|
||||
|
||||
private static void userNullCheck(User user) {
|
||||
if (user == null) {
|
||||
throw new RuntimeException("유저가 없습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
public Post savePost(User user, String title, String content) {
|
||||
userNullCheck(user);
|
||||
return postRepository.save(new Post(title, content, user));
|
||||
}
|
||||
|
||||
public void deletePost(User user, Long id) {
|
||||
userNullCheck(user);
|
||||
Post post = postRepository.findByIdAndUser(id, user);
|
||||
postRepository.delete(post);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.example.springsecuritystudy.post;
|
||||
|
||||
public enum PostStatus {
|
||||
Y,
|
||||
N
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -28,6 +29,7 @@ public class User implements UserDetails {
|
||||
private String password;
|
||||
private String authority;
|
||||
|
||||
@Builder
|
||||
public User(String username, String password, String authority) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
@@ -39,6 +41,10 @@ public class User implements UserDetails {
|
||||
return Collections.singleton((GrantedAuthority) () -> authority);
|
||||
}
|
||||
|
||||
public Boolean isAdmin() {
|
||||
return authority.equals("ROLE_ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
|
||||
@@ -4,23 +4,26 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/signup")
|
||||
public class UserController {
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
@GetMapping
|
||||
@GetMapping("/login")
|
||||
public String loginView() {
|
||||
return "login";
|
||||
}
|
||||
|
||||
@GetMapping("/signup")
|
||||
public String signupView() {
|
||||
return "signup";
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PostMapping("/signup")
|
||||
public String signup(@ModelAttribute UserDto userDto) {
|
||||
userService.signup(userDto.getUsername(), userDto.getPassword());
|
||||
return "redirect:login";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.example.springsecuritystudy.user;
|
||||
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.example.springsecuritystudy.common.AlreadyRegisteredUserException;
|
||||
import com.example.springsecuritystudy.common.UserNotFoundException;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Service
|
||||
@@ -14,22 +16,34 @@ public class UserService {
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public User signup(String username, String password) {
|
||||
if (userRepository.findByUsername(username).isPresent()) {
|
||||
throw new RuntimeException("이미 등록된 유저입니다.");
|
||||
}
|
||||
return userRepository.save(new User(username, passwordEncoder.encode(password), "ROLE_USER"));
|
||||
alreadyRegisteredUser(username);
|
||||
User user = User.builder()
|
||||
.username(username)
|
||||
.password(passwordEncoder.encode(password))
|
||||
.authority("ROLE_USER")
|
||||
.build();
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
public User signupAdmin(String username, String password) {
|
||||
if (userRepository.findByUsername(username).isPresent()) {
|
||||
throw new RuntimeException("이미 등록된 Admin유저입니다.");
|
||||
}
|
||||
return userRepository.save(new User(username, passwordEncoder.encode(password), "ROLE_ADMIN"));
|
||||
alreadyRegisteredUser(username);
|
||||
User user = User.builder()
|
||||
.username(username)
|
||||
.password(passwordEncoder.encode(password))
|
||||
.authority("ROLE_ADMIN")
|
||||
.build();
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
public User findByUsername(String username) {
|
||||
return userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("존재하지 않는 유저입니다."));
|
||||
.orElseThrow(UserNotFoundException::new);
|
||||
}
|
||||
|
||||
private void alreadyRegisteredUser(String username) {
|
||||
if (userRepository.findByUsername(username).isPresent()) {
|
||||
throw new AlreadyRegisteredUserException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ server:
|
||||
session:
|
||||
timeout: 10m # 기본 30분, 최소는 1분
|
||||
|
||||
# logging 레벨 설정
|
||||
logging:
|
||||
level:
|
||||
root: info
|
||||
org.springframework.web: debug
|
||||
sql: error
|
||||
root: INFO
|
||||
sql: ERROR
|
||||
# org.springframework.web: debug
|
||||
# org.springframework.security: debug
|
||||
|
||||
@@ -30,3 +30,6 @@
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
.row p {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
BIN
src/main/resources/static/images/spring-security.png
Normal file
BIN
src/main/resources/static/images/spring-security.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
@@ -8,7 +8,19 @@
|
||||
<header th:insert="fragments.html::nav"></header>
|
||||
<div class="container">
|
||||
<h1>관리자 페이지</h1>
|
||||
<p>당신은 관리자입니다.</p>
|
||||
<h3>게시글 내역</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<div th:each="note : ${notes}">
|
||||
<p style="margin: 10px 0;">
|
||||
<strong th:text="${note.title}"></strong>
|
||||
Posted by
|
||||
<strong th:if="${note.user}" th:text="${note.user.username}"></strong> on
|
||||
<strong th:text="${#temporals.format(note.createdAt, 'yyyy-MM-dd')}"></strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Welcome Spring Security Example</h1>
|
||||
<p>당신의 이름은 <span th:text="${name}">차현우</span> 입니다.</p>
|
||||
<p>당신의 나이는 <span th:text="${age}">0</span>살 입니다.</p>
|
||||
<p>변수는 <span th:with="temp=${name}" th:text="${temp}"></span>입니다.</p>
|
||||
<th:block th:if="${age < 30}"><p>당신은 30대가 아닙니다.</p></th:block>
|
||||
<th:block th:unless="${age < 30}"><p>당신은 30대 이상입니다.</p></th:block>
|
||||
<th:block th:switch="${name}">
|
||||
<p th:case="정우성"> 당신은 정씨 입니다.</p>
|
||||
<p th:case="감우성"> 당신은 감씨 입니다.</p>
|
||||
</th:block>
|
||||
<a href="/">홈으로</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,6 +8,7 @@
|
||||
<head th:fragment="header">
|
||||
<meta charset="UTF-8">
|
||||
<title>스프링 시큐리티 학습용</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/images/spring-security.png">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
|
||||
@@ -16,6 +17,7 @@
|
||||
rel="stylesheet"
|
||||
href="https://use.fontawesome.com/releases/v5.0.6/css/all.css"
|
||||
>
|
||||
<link rel="stylesheet" type="text/css" href="css/signin.css">
|
||||
<style>
|
||||
.nav-username {
|
||||
border-radius: 5px;
|
||||
@@ -65,9 +67,9 @@
|
||||
<a
|
||||
class="nav-link active"
|
||||
sec:authorize="hasAnyRole('ROLE_USER')"
|
||||
th:href="@{/post}"
|
||||
th:href="@{/note}"
|
||||
>
|
||||
게시글
|
||||
개인노트
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/signin.css">
|
||||
<head th:insert="fragments.html::header"></head>
|
||||
</head>
|
||||
<head th:insert="fragments.html::header"></head>
|
||||
<body>
|
||||
<header th:insert="fragments.html::nav"></header>
|
||||
<div class="container">
|
||||
@@ -17,6 +14,10 @@
|
||||
<label for="password" class="sr-only">Password</label>
|
||||
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
|
||||
</p>
|
||||
<div>
|
||||
<label for="remember-me">로그인 유지하기</label>
|
||||
<input type="checkbox" id="remember-me" name="remember-me" class="form-check-input mt-0" autocomplete="off">
|
||||
</div>
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">로그인</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
<header th:insert="fragments.html::nav"></header>
|
||||
<!-- 개인 user만 접근할 수 있는 페이지 -->
|
||||
<div class="container">
|
||||
<h1>게시글</h1>
|
||||
<h1>개인노트</h1>
|
||||
|
||||
<!-- Button trigger modal -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#newPostModal"
|
||||
data-bs-target="#newNoteModal"
|
||||
data-bs-whatever="@mdo">
|
||||
새 글 쓰기
|
||||
</button>
|
||||
@@ -28,7 +28,7 @@
|
||||
<!-- Modal -->
|
||||
<div
|
||||
class="modal fade"
|
||||
id="newPostModal"
|
||||
id="newNoteModal"
|
||||
tabindex="-1"
|
||||
aria-labelledby="newPostModalLabel"
|
||||
aria-hidden="true"
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="newPostModalLabel">새 글 쓰기</h5>
|
||||
<h5 class="modal-title" id="newNoteModalLabel">새 글 쓰기</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
@@ -45,7 +45,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<form
|
||||
th:action="@{/post}"
|
||||
th:action="@{/note}"
|
||||
method="post"
|
||||
>
|
||||
<div class="modal-body">
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="content" class="col-form-label">내용</label>
|
||||
<textarea class="form-control" id="content" name="content"></textarea>
|
||||
<textarea class="form-control" rows="20" id="content" name="content"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -69,15 +69,15 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
|
||||
<div class="border border-dark" th:each="post : ${posts}">
|
||||
<h2 th:text="${post.title}"></h2>
|
||||
<div class="border border-dark" th:each="note : ${notes}">
|
||||
<h2 th:text="${note.title}"></h2>
|
||||
<div>
|
||||
<p th:text="${post.content}"></p>
|
||||
<form th:action="@{/post}" th:method="delete">
|
||||
<input type="hidden" name="id" th:value="${post.id}">
|
||||
<span style="margin: 10px 0px;">Posted by
|
||||
<strong th:if="${post.user}" th:text="${post.user.username}"></strong> on
|
||||
<strong th:text="${#temporals.format(post.createdAt, 'yyyy-MM-dd')}"></strong>
|
||||
<p th:text="${note.content}"></p>
|
||||
<form th:action="@{/note}" th:method="delete">
|
||||
<input type="hidden" name="id" th:value="${note.id}">
|
||||
<span style="margin: 10px 0;">Posted On
|
||||
<strong th:if="${note.user}" th:text="${note.user.username}"></strong> on
|
||||
<strong th:text="${#temporals.format(note.createdAt, 'yyyy-MM-dd')}"></strong>
|
||||
</span>
|
||||
<button type="submit" class="btn btn-secondary">삭제</button>
|
||||
</form>
|
||||
@@ -4,7 +4,12 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
|
||||
>
|
||||
<head th:insert="fragments.html::header"></head>
|
||||
<head>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<head th:insert="fragments.html::header"></head>
|
||||
</head>
|
||||
<body>
|
||||
<header th:insert="fragments.html::nav"></header>
|
||||
<div class="container">
|
||||
@@ -51,7 +56,7 @@
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="content" class="col-form-label">내용</label>
|
||||
<textarea class="form-control" id="content" name="content"></textarea>
|
||||
<textarea class="form-control" rows="20" id="content" name="content"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -71,7 +76,7 @@
|
||||
<p th:text="${notice.content}"></p>
|
||||
<form th:action="@{/notice}" th:method="delete">
|
||||
<input type="hidden" name="id" th:value="${notice.id}">
|
||||
<span style="margin: 10px 0px;">Posted At
|
||||
<span style="margin: 10px 0;">Posted On
|
||||
<strong th:text="${#temporals.format(notice.createdAt, 'yyyy-MM-dd')}"></strong>
|
||||
</span>
|
||||
<button
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
lang="ko"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="css/signin.css">
|
||||
<head th:insert="fragments.html::header"></head>
|
||||
</head>
|
||||
<head th:insert="fragments.html::header"></head>
|
||||
<body>
|
||||
<header th:insert="fragments.html::nav"></header>
|
||||
<div class="container">
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.example.springsecuritystudy;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
@SpringBootTest
|
||||
class SampleControllerTest {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext applicationContext;
|
||||
private MockMvc mvc;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(applicationContext)
|
||||
.apply(springSecurity())
|
||||
.alwaysDo(print())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void example() throws Exception {
|
||||
mvc.perform(
|
||||
get("/example")
|
||||
).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_user() throws Exception {
|
||||
mvc.perform(
|
||||
formLogin("/login")
|
||||
.user("user")
|
||||
.password("user")
|
||||
).andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
void login_admin() throws Exception {
|
||||
mvc.perform(
|
||||
formLogin("/login")
|
||||
.user("admin")
|
||||
.password("admin")
|
||||
).andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void access_user() throws Exception {
|
||||
mvc.perform(
|
||||
get("/user")
|
||||
).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockAdmin
|
||||
void access_admin() throws Exception {
|
||||
mvc.perform(
|
||||
get("/admin")
|
||||
).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void access_denied() throws Exception {
|
||||
mvc.perform(
|
||||
get("/admin")
|
||||
).andExpect(status().isForbidden());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.example.springsecuritystudy.admin;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.example.springsecuritystudy.helper.TestConfig;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
import com.example.springsecuritystudy.user.UserRepository;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
class AdminControllerTest extends TestConfig {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
private MockMvc mvc;
|
||||
private User user;
|
||||
private User admin;
|
||||
|
||||
@BeforeEach
|
||||
void setUp(@Autowired WebApplicationContext applicationContext) {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(applicationContext)
|
||||
.apply(springSecurity())
|
||||
.alwaysDo(print())
|
||||
.build();
|
||||
user = userRepository.save(new User("user", "user", "ROLE_USER"));
|
||||
admin = userRepository.save(new User("admin", "admin", "ROLE_ADMIN"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNoteForAdmin_인증없음() throws Exception {
|
||||
mvc.perform(
|
||||
get("/admin").with(csrf())
|
||||
).andExpect(redirectedUrlPattern("**/login"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNoteForAdmin_어드민인증있음() throws Exception {
|
||||
mvc.perform(
|
||||
get("/admin").with(csrf()).with(user(admin))
|
||||
).andExpect(status().is2xxSuccessful());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNoteForAdmin_유저인증있음() throws Exception {
|
||||
mvc.perform(
|
||||
get("/admin").with(csrf()).with(user(user))
|
||||
).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.springsecuritystudy.helper;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@SpringBootTest
|
||||
@ActiveProfiles(value = "test")
|
||||
@Transactional
|
||||
public class TestConfig {
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.springsecuritystudy;
|
||||
package com.example.springsecuritystudy.helper;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.TestExecutionEvent;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.example.springsecuritystudy.helper.TestConfig;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
import com.example.springsecuritystudy.user.UserRepository;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
class NoteControllerTest extends TestConfig {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired
|
||||
private NoteRepository noteRepository;
|
||||
private MockMvc mvc;
|
||||
private User user;
|
||||
private User admin;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(@Autowired WebApplicationContext applicationContext) {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(applicationContext)
|
||||
.apply(springSecurity())
|
||||
.alwaysDo(print())
|
||||
.build();
|
||||
User user2 = User.builder()
|
||||
.username("user123")
|
||||
.password("user")
|
||||
.authority("ROLE_USER")
|
||||
.build();
|
||||
User admin2 = User.builder()
|
||||
.username("admin123")
|
||||
.password("admin")
|
||||
.authority("ROLE_ADMIN")
|
||||
.build();
|
||||
this.user = userRepository.save(user2);
|
||||
this.admin = userRepository.save(admin2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNote_인증없음() throws Exception {
|
||||
mvc.perform(
|
||||
get("/note")
|
||||
).andExpect(redirectedUrlPattern("**/login"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
//WithUserDetails 로 테스트 하는 방법
|
||||
@WithUserDetails(
|
||||
value = "user123", // userDetailsService를 통해 가져올 수 있는 유저
|
||||
userDetailsServiceBeanName = "userDetailServiceImpl", // UserDetailsService 구현체의 Bean
|
||||
setupBefore = TestExecutionEvent.TEST_EXECUTION // 테스트 실행 직전에 유저를 가져온다.
|
||||
)
|
||||
void getNote_인증있음() throws Exception {
|
||||
mvc.perform(
|
||||
get("/note")
|
||||
).andExpect(status().isOk())
|
||||
.andExpect(view().name("note/index"))
|
||||
.andDo(print());
|
||||
}
|
||||
|
||||
@Test
|
||||
void postNote_인증없음() throws Exception {
|
||||
mvc.perform(
|
||||
post("/note").with(csrf())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("title", "제목")
|
||||
.param("content", "내용")
|
||||
).andExpect(redirectedUrlPattern("**/login"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(
|
||||
value = "admin123",
|
||||
userDetailsServiceBeanName = "userDetailServiceImpl",
|
||||
setupBefore = TestExecutionEvent.TEST_EXECUTION
|
||||
)
|
||||
void postNote_어드민인증있음() throws Exception {
|
||||
mvc.perform(
|
||||
post("/note").with(csrf())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("title", "제목")
|
||||
.param("content", "내용")
|
||||
).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(
|
||||
value = "user123",
|
||||
userDetailsServiceBeanName = "userDetailServiceImpl",
|
||||
setupBefore = TestExecutionEvent.TEST_EXECUTION
|
||||
)
|
||||
void postNote_유저인증있음() throws Exception {
|
||||
mvc.perform(
|
||||
post("/note").with(csrf())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("title", "제목")
|
||||
.param("content", "내용")
|
||||
).andExpect(redirectedUrl("note"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteNote_인증없음() throws Exception {
|
||||
Note note = noteRepository.save(new Note("제목", "내용", user));
|
||||
mvc.perform(
|
||||
delete("/note?id=" + note.getId()).with(csrf())
|
||||
).andExpect(redirectedUrlPattern("**/login"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(
|
||||
value = "user123",
|
||||
userDetailsServiceBeanName = "userDetailServiceImpl",
|
||||
setupBefore = TestExecutionEvent.TEST_EXECUTION
|
||||
)
|
||||
void deleteNote_인증있음() throws Exception {
|
||||
Note note = noteRepository.save(new Note("제목", "내용", user));
|
||||
mvc.perform(
|
||||
delete("/note?id=" + note.getId()).with(csrf())
|
||||
).andExpect(redirectedUrl("note"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(
|
||||
value = "admin123",
|
||||
userDetailsServiceBeanName = "userDetailServiceImpl",
|
||||
setupBefore = TestExecutionEvent.TEST_EXECUTION
|
||||
)
|
||||
void deleteNote_어드민계정있음() throws Exception {
|
||||
Note note = noteRepository.save(new Note("제목", "내용", user));
|
||||
mvc.perform(
|
||||
delete("/note?id=" + note.getId()).with(csrf())
|
||||
).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.example.springsecuritystudy.note;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.example.springsecuritystudy.helper.TestConfig;
|
||||
import com.example.springsecuritystudy.user.User;
|
||||
import com.example.springsecuritystudy.user.UserService;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.*;
|
||||
|
||||
class NoteServiceTest extends TestConfig {
|
||||
|
||||
@Autowired
|
||||
private NoteService noteService;
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
void findByUser_유저가_게시물조회() {
|
||||
//given
|
||||
User user = userService.signup("user", "user");
|
||||
noteService.saveNote(user, "title1", "content1");
|
||||
noteService.saveNote(user, "title2", "content2");
|
||||
//when
|
||||
List<Note> notes = noteService.findByUser(user);
|
||||
//then
|
||||
then(notes.size()).isEqualTo(2);
|
||||
Note note1 = notes.get(0);
|
||||
Note note2 = notes.get(1);
|
||||
|
||||
// post1 = title2
|
||||
then(note1.getUser().getUsername()).isEqualTo("user");
|
||||
then(note1.getTitle()).isEqualTo("title2");
|
||||
then(note1.getContent()).isEqualTo("content2");
|
||||
// post2 = title1
|
||||
then(note2.getUser().getUsername()).isEqualTo("user");
|
||||
then(note2.getTitle()).isEqualTo("title1");
|
||||
then(note2.getContent()).isEqualTo("content1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByUser_어드민이_조회() {
|
||||
// given
|
||||
User admin = userService.signupAdmin("admin", "admin");
|
||||
User user1 = userService.signup("user1", "user1");
|
||||
User user2 = userService.signup("user2", "user2");
|
||||
noteService.saveNote(user1, "title1", "content1");
|
||||
noteService.saveNote(user1, "title2", "content2");
|
||||
noteService.saveNote(user2, "title3", "content3");
|
||||
// when
|
||||
List<Note> notes = noteService.findByUser(admin);
|
||||
// then
|
||||
then(notes.size()).isEqualTo(3);
|
||||
Note note1 = notes.get(0);
|
||||
Note note2 = notes.get(1);
|
||||
Note note3 = notes.get(2);
|
||||
|
||||
// post1 = title3
|
||||
then(note1.getUser().getUsername()).isEqualTo("user2");
|
||||
then(note1.getTitle()).isEqualTo("title3");
|
||||
then(note1.getContent()).isEqualTo("content3");
|
||||
// post1 = title2
|
||||
then(note2.getUser().getUsername()).isEqualTo("user1");
|
||||
then(note2.getTitle()).isEqualTo("title2");
|
||||
then(note2.getContent()).isEqualTo("content2");
|
||||
// post1 = title1
|
||||
then(note3.getUser().getUsername()).isEqualTo("user1");
|
||||
then(note3.getTitle()).isEqualTo("title1");
|
||||
then(note3.getContent()).isEqualTo("content1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void savePost() {
|
||||
// given
|
||||
User user = userService.signup("user", "user");
|
||||
// when
|
||||
noteService.saveNote(user, "title", "content");
|
||||
// then
|
||||
then(noteService.findByUser(user).size()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deletePost() {
|
||||
// given
|
||||
User user = userService.signup("user", "user");
|
||||
Note note = noteService.saveNote(user, "title", "content");
|
||||
// when
|
||||
noteService.deleteNote(user, note.getId());
|
||||
// then
|
||||
then(noteService.findByUser(user).size()).isZero();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.example.springsecuritystudy.notice;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.example.springsecuritystudy.helper.TestConfig;
|
||||
import com.example.springsecuritystudy.helper.WithMockAdmin;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
class NoticeControllerTest extends TestConfig {
|
||||
|
||||
@Autowired
|
||||
private NoticeRepository noticeRepository;
|
||||
private MockMvc mvc;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(@Autowired WebApplicationContext applicationContext) {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(applicationContext)
|
||||
.apply(springSecurity())
|
||||
.alwaysDo(print())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNotice_인증없음() throws Exception {
|
||||
mvc.perform(get("/notice"))
|
||||
.andExpect(redirectedUrlPattern("**/login"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void getNotice_인증있음() throws Exception {
|
||||
mvc.perform(get("/notice"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("notice/index"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void postNotice_인증없음() throws Exception {
|
||||
mvc.perform(post("/notice")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("title", "제목")
|
||||
.param("content", "내용")
|
||||
).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(roles = "USER", username = "user", password = "user")
|
||||
void postNotice_유저인증있음() throws Exception {
|
||||
mvc.perform(post("/notice")
|
||||
.with(csrf())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("title", "제목")
|
||||
.param("content", "내용")
|
||||
).andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockAdmin
|
||||
void postNotice_어드민인증있음() throws Exception {
|
||||
mvc.perform(post("/notice")
|
||||
.with(csrf())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("title", "제목")
|
||||
.param("content", "내용")
|
||||
).andExpect(redirectedUrl("notice"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteNotice_인증없음() throws Exception {
|
||||
Notice notice = noticeRepository.save(new Notice("제목", "내용"));
|
||||
mvc.perform(delete("/notice?id=" + notice.getId()))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(roles = "USER", username = "user", password = "user")
|
||||
void deleteNotice_유저인증있음() throws Exception {
|
||||
Notice notice = noticeRepository.save(new Notice("제목", "내용"));
|
||||
mvc.perform(delete("/notice?id=" + notice.getId())
|
||||
.with(csrf()))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockAdmin
|
||||
void deleteNotice_어드민인증있음() throws Exception {
|
||||
Notice notice = noticeRepository.save(new Notice("제목", "내용"));
|
||||
mvc.perform(delete("/notice?id=" + notice.getId())
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("notice"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.example.springsecuritystudy.user;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.example.springsecuritystudy.helper.TestConfig;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
class UserControllerTest extends TestConfig {
|
||||
|
||||
private MockMvc mvc;
|
||||
|
||||
@BeforeEach
|
||||
void setUp(@Autowired WebApplicationContext context) {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(context)
|
||||
.apply(springSecurity())
|
||||
.alwaysDo(print())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void signup() throws Exception {
|
||||
mvc.perform(
|
||||
post("/signup").with(csrf())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param("username", "user123")
|
||||
.param("password", "password")
|
||||
).andExpect(redirectedUrl("login"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.example.springsecuritystudy.user;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.example.springsecuritystudy.helper.TestConfig;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class UserServiceTest extends TestConfig {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Test
|
||||
void signup() {
|
||||
//given
|
||||
String username = "user123";
|
||||
String password = "password";
|
||||
//when
|
||||
User user = userService.signup(username, password);
|
||||
//then
|
||||
then(user.getId()).isNotNull();
|
||||
then(user.getUsername()).isEqualTo(username);
|
||||
then(user.getPassword()).startsWith("{bcrypt}");
|
||||
then(user.getAuthorities()).hasSize(1);
|
||||
then(user.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo("ROLE_USER");
|
||||
then(user.isAdmin()).isFalse();
|
||||
then(user.isAccountNonExpired()).isTrue();
|
||||
then(user.isAccountNonLocked()).isTrue();
|
||||
then(user.isEnabled()).isTrue();
|
||||
then(user.isCredentialsNonExpired()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void signupAdmin() {
|
||||
//given
|
||||
String username = "admin123";
|
||||
String password = "password";
|
||||
//when
|
||||
User user = userService.signupAdmin(username, password);
|
||||
//then
|
||||
then(user.getId()).isNotNull();
|
||||
then(user.getUsername()).isEqualTo(username);
|
||||
then(user.getPassword()).startsWith("{bcrypt}");
|
||||
then(user.getAuthorities()).hasSize(1);
|
||||
then(user.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo("ROLE_ADMIN");
|
||||
then(user.isAdmin()).isTrue();
|
||||
then(user.isAccountNonExpired()).isTrue();
|
||||
then(user.isAccountNonLocked()).isTrue();
|
||||
then(user.isEnabled()).isTrue();
|
||||
then(user.isCredentialsNonExpired()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByUsername() {
|
||||
//given
|
||||
User user = User.builder()
|
||||
.username("user123")
|
||||
.password("password")
|
||||
.authority("ROLE_USER")
|
||||
.build();
|
||||
userRepository.save(user);
|
||||
//when
|
||||
User savedUser = userService.findByUsername("user123");
|
||||
//then
|
||||
then(savedUser.getId()).isNotNull();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user