Mdofiy 관리자페이지 게시글내역 히스토리 볼수 있도록 수정, securityConfig 순환참조 오류 수정

This commit is contained in:
Daeil Choi
2023-02-06 09:47:25 +09:00
parent b5c06cf76f
commit de564ef4fe
15 changed files with 154 additions and 47 deletions

View File

@@ -0,0 +1,12 @@
package com.example.springsecuritystudy.common;
public class AlreadyRegisteredUserException extends RuntimeException {
public AlreadyRegisteredUserException(String message) {
super(message);
}
public AlreadyRegisteredUserException() {
super("이미 등록된 유저입니다.");
}
}

View File

@@ -0,0 +1,32 @@
package com.example.springsecuritystudy.config;
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Configuration;
import com.example.springsecuritystudy.notice.NoticeService;
import com.example.springsecuritystudy.post.PostService;
import com.example.springsecuritystudy.user.User;
import com.example.springsecuritystudy.user.UserService;
import lombok.RequiredArgsConstructor;
@Configuration
@RequiredArgsConstructor
public class InitializeConfig {
private final UserService userService;
private final PostService postService;
private final NoticeService noticeService;
@PostConstruct
public void adminAccount() {
User user = userService.signup("user", "user");
userService.signupAdmin("admin", "admin");
postService.savePost(user, "테스트", "테스트입니다.");
postService.savePost(user, "테스트2", "테스트2입니다.");
postService.savePost(user, "테스트3", "테스트3입니다.");
postService.savePost(user, "여름 여행계획", "여름 여행계획 작성중...");
noticeService.saveNotice("환영합니다", "환영합니다 여러분");
}
}

View File

@@ -3,18 +3,9 @@ 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;
@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(){

View File

@@ -4,28 +4,21 @@ import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
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.util.matcher.AntPathRequestMatcher;
import com.example.springsecuritystudy.user.UserRepository;
import lombok.RequiredArgsConstructor;
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final UserRepository userRepository;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.antMatchers("/", "/home", "/signup", "/example",
"/css/**", "/js/**", "/h2-console/**").permitAll()
"/css/**", "/h2-console/**").permitAll()
.antMatchers("/post").hasRole("USER")
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers(HttpMethod.POST, "/notice").hasRole("ADMIN")
@@ -48,14 +41,4 @@ public class SecurityConfig {
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring().antMatchers("/css/**", "/js/**", "/h2-console/**");
}
@Bean
public UserDetailsService userDetailsService() {
return username -> userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("유저를 찾지 못 했습니다."));
}
}

View File

@@ -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);
}
}

View File

@@ -7,6 +7,11 @@ import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class SampleController {
@GetMapping({"/", "/home"})
public String index() {
return "index";
}
@GetMapping("/example")
public String example(Model model) {
model.addAttribute("name", "정우성");

View File

@@ -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) {

View File

@@ -0,0 +1,29 @@
package com.example.springsecuritystudy.post;
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.user.User;
import lombok.RequiredArgsConstructor;
@Controller
@RequiredArgsConstructor
@RequestMapping("/admin")
public class AdminController {
private final PostService postService;
@GetMapping
public String getPostForAdmin(Authentication authentication, Model model) {
User user = (User) authentication.getPrincipal();
List<Post> posts = postService.findByUser(user);
model.addAttribute("posts", posts);
return "admin/index";
}
}

View File

@@ -43,4 +43,9 @@ public class Post extends BaseTimeEntity {
this.status = PostStatus.Y;
this.user = user;
}
public void updatePost(String title, String content) {
this.title = title;
this.content = content;
}
}

View File

@@ -24,7 +24,7 @@ public class PostController {
private final PostService postService;
@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);

View File

@@ -8,7 +8,9 @@ import com.example.springsecuritystudy.user.User;
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByUserAndStatus(User user, PostStatus status);
List<Post> findByUserAndStatusOrderByIdDesc(User user, PostStatus status);
Post findByIdAndUser(Long id, User user);
List<Post> findByStatusOrderByIdDesc(PostStatus status);
}

View File

@@ -5,8 +5,8 @@ import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.springsecuritystudy.common.UserNotFoundException;
import com.example.springsecuritystudy.user.User;
import com.example.springsecuritystudy.user.UserRepository;
import lombok.RequiredArgsConstructor;
@@ -15,18 +15,20 @@ import lombok.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);
if (Boolean.TRUE.equals(user.isAdmin())) {
return postRepository.findByStatusOrderByIdDesc(PostStatus.Y);
}
return postRepository.findByUserAndStatusOrderByIdDesc(user, PostStatus.Y);
}
private static void userNullCheck(User user) {
if (user == null) {
throw new RuntimeException("유저가 없습니다.");
throw new UserNotFoundException();
}
}

View File

@@ -4,18 +4,21 @@ 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";
}

View File

@@ -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,24 @@ public class UserService {
private final PasswordEncoder passwordEncoder;
public User signup(String username, String password) {
if (userRepository.findByUsername(username).isPresent()) {
throw new RuntimeException("이미 등록된 유저입니다.");
}
alreadyRegisteredUser(username);
return userRepository.save(new User(username, passwordEncoder.encode(password), "ROLE_USER"));
}
public User signupAdmin(String username, String password) {
if (userRepository.findByUsername(username).isPresent()) {
throw new RuntimeException("이미 등록된 Admin유저입니다.");
}
alreadyRegisteredUser(username);
return userRepository.save(new User(username, passwordEncoder.encode(password), "ROLE_ADMIN"));
}
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();
}
}
}

View File

@@ -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="post : ${posts}">
<p style="margin: 10px 0;">
<strong th:text="${post.title}"></strong>
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>
</div>
</div>
</div>
</div>
</body>
</html>