스프링 부트 쇼핑몰 프로젝트 with JPA (5)
스프링 시큐리티를 이용한 회원가입 및 로그인 -2
📌 로그인/로그아웃 구현하기
UserDetailsService 인터페이스
👉🏻 데이터베이스에서 회원 정보 가져옴.
👉🏻 localUserByUsername() 메소드 존재. 회원 정보 조회하여 사용자의 정보와 권한을 갖는 UserDetails 인터페이스 반환
UserDetail 인터페이스
👉🏻 스프링 시큐리티에서 회원의 정보를 담기 위해 사용하는 인터페이스
👉🏻 직접 구현 OR 스프링 시큐리티에서 제공하는 User 클래스(UserDetails 인터페이스를 구현하고 있는 클래스) 사용
기존의 MemberService가 UserDetailsService를 구현하게 하자.
package com.shop.service;
import com.shop.entity.Member;
import com.shop.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.User;
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;
@Service
@Transactional
@RequiredArgsConstructor
public class MemberService implements UserDetailsService {
private final MemberRepository memberRepository;
public Member saveMember(Member member){
validateDuplicateMember(member);
return memberRepository.save(member);
}
private void validateDuplicateMember(Member member){
Member findMember = memberRepository.findByEmail(member.getEmail());
if(findMember != null) {
throw new IllegalStateException("이미 가입된 회원입니다.");
}
}
//로그인 할 User의 email을 파라미터로 전달받음.
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Member member = memberRepository.findByEmail(email);
if(member == null){
throw new UsernameNotFoundException(email);
}
//UserDetail을 구현하는 User 객체를 반환.
//User 객체를 생성하기 위해 회원의 정보를 넘겨 줌.
return User.builder()
.username(member.getName())
.password(member.getPassword())
.roles(member.getRole().toString())
.build();
}
}
👆🏻MemberService가 UserDetailsService를 구현함. loadUserByUsername메소드를 오버라이딩 하고, 로그인 할 User의 email을 파라미터로 전달받음. UserDetail을 구현하는 User 객체를 생성하고 반환함.
Securityconfig
package com.shop.config;
import com.shop.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SecutiryConfig extends WebSecurityConfigurerAdapter {
@Autowired
MemberService memberService;
//http 요청에 대한 보안 설정 (페이지 권한, 로그인 페이지, 로그아웃 메서드 설정 작성)
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin()
.loginPage("/members/login")
.defaultSuccessUrl("/")
.usernameParameter("email")
.failureUrl("/members/login/error")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/members/logout"))
.logoutSuccessUrl("/");
}
//BCryptPasswordEncoder() 해쉬함수 이용해서 비밀번호를 암호화
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//spring Security에서 인증은 AuthenticationManagerBuilder 통해 이뤄짐
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(memberService) //userDetail을 구현하는 객체로 memberService 지정
.passwordEncoder(passwordEncoder()); //비밀번호 암호화
}
}
👆🏻configure 메소드에서 로그인 페이지 URL을 설정, 로그인 성공 시 이동할 URL 설정, 로그인 시 사용할 파라미터 이름으로 email을 지정, 로그인 실패시 이동할 URL 설정, 로그아웃 URL을 설정함.
👆🏻스프링 시큐리티에서 인증은 AuthenticationManagerBuilder가 생성한 AuthenticationManeger을 통해 함.
Controller
package com.shop.controller;
import com.shop.dto.MemberFormDto;
import com.shop.entity.Member;
import com.shop.service.MemberService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
@Controller
@RequestMapping("/members")
@RequiredArgsConstructor
public class MemberController {
....코드 생략.....
@GetMapping("/login")
public String loginMember(){
return "member/memberLoginForm";
}
@GetMapping("/login/error")
public String loginError(Model model){
model.addAttribute("loginErrorMsg", "아이디 또는 비밀번호를 확인해주세요");
return "/member/memberLoginForm";
}
}
📌 실행화면
<로그인 화면>
<로그인 실패>
<로그인 성공>
📌 페이지 권한 설정하기
👉🏻 상품 등록 페이지는 ADMIN 계정만 가능하게 설정함.
ItemController
package com.shop.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ItemController {
@GetMapping("/admin/item/new")
public String itemForm(){
return "/item/itemForm";
}
}
👆🏻상품 등록 페이지로 접근할 수 있도록 Controller에 설정함.
package com.shop.config;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
👆🏻AuthenticationEntryPoint 인터페이스를 통해 인증되지 않은 사용자가 리소스를 요청할 경우 에러가 발생하도록 함.
SecutiryConfig
@Override
protected void configure(HttpSecurity http) throws Exception{
.....코드 생략....
http.authorizeRequests()
.mvcMatchers("/", "/members/**",
"/item/**", "/images/**").permitAll()
.mvcMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
http.exceptionHandling()
.authenticationEntryPoint(
new CustomAuthenticationEntryPoint());
}
@Override
public void configure(WebSecurity web) throws Exception{
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**");
}
Author And Source
이 문제에 관하여(스프링 부트 쇼핑몰 프로젝트 with JPA (5)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@uuuuu_j_/스프링-부트-쇼핑몰-프로젝트-with-JPA-저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)