Spring Security 2022/04/05

무간·2022년 4월 5일
0

스프링 시큐리티

- 홈화면(로그인 전에)
127.0.0.1:9090/ROOT/security_home
127.0.0.1:9090/ROOT/member/security_join
127.0.0.1:9090/ROOT/member/security_login

- 관리자 홈화면(로그인 후에)
127.0.0.1:9090/ROOT/security_admin/home
127.0.0.1:9090/ROOT/security_admin/insert

- 판매자 홈화면(로그인 후에)
127.0.0.1:9090/ROOT/security_seller/home
127.0.0.1:9090/ROOT/security_seller/item

- 고객 홈화면(로그인 후에)
127.0.0.1:9090/ROOT/security_customer/home
127.0.0.1:9090/ROOT/security_customer/mypage

파일명 pom.xml

<!-- spring security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

파일명 SecurityController.java

package com.example.controller;

import com.example.dto.MemberDTO;
import com.example.dto.MyUserDTO;
import com.example.mapper.MemberMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class SecurityController {

    @Autowired MemberMapper mMapper;

    @GetMapping(value = {"/security_403"})
    public String security403GET(){
        return "/security/403page";
    }
    
    // 로그인과 상관없이 보여지는 홈화면
    // 127.0.0.1:9090/ROOT/security_home
    @GetMapping(value = {"/security_home"})
    public String securityhomeGET(
        Model model,
        @AuthenticationPrincipal MyUserDTO user
    ){
        if(user != null){
            System.out.println(user.getName());            
            System.out.println(user.getUserphone());
            System.out.println(user.getUsername());
            System.out.println(user.getAuthorities().toArray()[0]);
         }
        model.addAttribute("user",user);
        // model.addAttribute("userid",user.getUsername());
        // model.addAttribute("userrole",user.getAuthorities().toArray()[0]);
        return "/security/home";
    }

    // 관리자 로그인후에 보여지는 홈화면
    // 127.0.0.1:9090/ROOT/security_asmin/home
    @GetMapping(value = {"/security_admin/home"})
    public String securityAdminhomeGET(){
        return "/security/admin_home";
    }

    // 판매자 로그인후에 보여지는 홈화면
    // 127.0.0.1:9090/ROOT/security_seller/home
    @GetMapping(value = {"/security_seller/home"})
    public String securitySellerhomeGET(){
        return "/security/seller_home";
    }

    // 고객 로그인후에 보여지는 홈화면
    // 127.0.0.1:9090/ROOT/security_customer/home
    @GetMapping(value = {"/security_customer/home"})
    public String securityCustomerhomeGET(){
        return "/security/customer_home";
    }

    // 127.0.0.1:9090/ROOT/customer/security_join
    @GetMapping(value = "/member/security_join")
    public String securityJoinGET(){
        return "/security/join";
    }

    @PostMapping(value = "/member/security_join")
    public String SecurityJoinPOST(
        @ModelAttribute MemberDTO member
    ){
        BCryptPasswordEncoder bcpe = new BCryptPasswordEncoder();
        // 암호를 가져와서 해시한후 다시 추가하기
        member.setUpw(bcpe.encode(member.getUpw()));
        member.setUrole("CUSTOMER");

        int ret = mMapper.memberJoin(member);
        if(ret ==1){ // 성공시
            return "redirect:/security_home";
        }
        // 실패시
        return "redirect:/member/security_join";
    }

    @GetMapping(value="/member/security_login")
    public String securityLoginGET(){
        return "/security/login";
    }
}

파일명 SecurityConfig.java

package com.example.config;

import com.example.service.UserDetailsServiceImpl;

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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	// 1. 직접 만든 detailService 객체 가져오기
	@Autowired
	UserDetailsServiceImpl detailsService;    
		
	// 회원가입시 암호화 했던 방법의 객체생성
	// 2. 암호화 방법 객체 생성, @Bean은 서버 구동시 자동으로 객체 생성됨
	@Bean
	public BCryptPasswordEncoder bCryptPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}
		
	// 3. 직접만든 detailsService에 암호화 방법 적용
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(detailsService)
			.passwordEncoder( bCryptPasswordEncoder() );
	}	
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// super.configure(http);
		
		// 페이지별 접근 권한 설정
		http.authorizeRequests()
			.antMatchers("/admin","/admin/**")
				.hasAuthority("ADMIN")
			.antMatchers("/seller","/seller/**")
				.hasAnyAuthority("ADMIN", "SELLER")
			.antMatchers("/customer","/customer/**")
				.hasAuthority("CUSTOMER")
			.anyRequest().permitAll();	
		
		// 로그인 페이지 설정, 단 POST는 직접 만들지 않음
		http.formLogin()
			.loginPage("/member/login")
			.loginProcessingUrl("/member/loginaction")
			.usernameParameter("uemail")
			.passwordParameter("upw")
			.defaultSuccessUrl("/home")
			.permitAll();
		
		// 로그아웃 페이지 설정, url에 맞게 POST로 호출하면 됨.
		http.logout()
			.logoutUrl("/member/logout")
			.logoutSuccessUrl("/home")
			//.logoutSuccessHandler(new MyLogoutSuccessHandler())
			.invalidateHttpSession(true)
			.clearAuthentication(true)
			.permitAll();
			
		// 접근권한불가 403
		http.exceptionHandling().accessDeniedPage("/page403");		
		
		// h2-console을 사용하기 위해서
		http.csrf().ignoringAntMatchers("/h2-console/**");
		http.headers().frameOptions().sameOrigin();

		http.csrf().ignoringAntMatchers("/api/**");
	}
	
}

파일명 MemberMapper.java

package com.example.mapper;

import com.example.dto.MemberDTO;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface MemberMapper {

    // 회원가입
    // INSERT INTO 테이블명(컬럼명들) VALUES(추가할 값들)
    @Insert({
        "INSERT INTO MEMBER( UEMAIL, UPW, UNAME, UPHONE, UROLE, UREGDATE )",
        " VALUES( #{ obj.uemail }, #{ obj.upw }, #{ obj.uname }", 
            " , #{ obj.uphone }, #{ obj.urole }, CURRENT_DATE ) "
    })
    public int memberJoin( @Param(value = "obj") MemberDTO member);
    
    // 로그인
    // SELECT 컬럼명들 FROM 테이블명 WHERE 조건 AND 조건
    @Select({
        "SELECT UEMAIL, UNAME, UROLE FROM MEMBER WHERE UEMAIL = #{email} AND UPW = #{pw}"
    })
    public MemberDTO memberLogin(
        @Param(value = "email") String em,
        @Param(value = "pw") String userpw);

    // security 로그인
    // SELECT 컬럼명들 FROM 테이블명 WHERE 조건
    @Select({
        "SELECT UEMAIL, UPW, UROLE, UPHONE, UNAME FROM MEMBER WHERE UEMAIL = #{email}"
    })
    public MemberDTO memberEmail(
        @Param(value = "email") String em);    
}

파일명 MemberDetailServiceImpl.java

package com.example.service;

import java.util.Collection;

import com.example.dto.MemberDTO;
import com.example.dto.MyUserDTO;
import com.example.mapper.MemberMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
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;

@Service
public class MemberDetailServiceImpl implements UserDetailsService {

    @Autowired MemberMapper mMapper;
    
    // 로그인에서 입력하는 정보중에서 아이디를 받음
    // MemberMapper를 이용해서 정보를 가져와서 UserDetails로 리턴
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("MemberDetailService : "+ username);
        MemberDTO member = mMapper.memberEmail(username);

        // 권한정보를 문자열 배열로 만듬
        String[] strRole = {member.getUrole()};

        // String 배열 권한을 Collection<GrantedAuthority>로 변환함
        Collection<GrantedAuthority> roles = AuthorityUtils.createAuthorityList(strRole);
        // 아이디, 암호, 권한들...리턴
        // User user = new User(member.getUemail(),member.getUpw(), roles);

        MyUserDTO user = new MyUserDTO(member.getUemail(), member.getUpw(), roles, member.getUphone(), member.getUname());
        return user;
    }    
}

파일명 MyUserDTO.java

package com.example.dto;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper=false)
public class MyUserDTO extends User {

    private static final long serialVersionUID = 1L;
    private String username = null;
    private String password = null;
    private String userphone = null;
    private String name = null;

    public MyUserDTO(
            String username, 
            String password,
            Collection<? extends GrantedAuthority> authorities,
            String userphone,
            String name) {

        super(username, password, authorities);        
        this.username = username;
        this.password = password;
        this.userphone = userphone;
        this.name = name;
    }    
}

파일명 MyLoginSuccessHandler.java

package com.example.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

// 로그인 성공했을 때 자동으로 호출되는 handler
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler{

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request, 
            HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {

        System.out.println("LoginSuccessHandler");

        User user = (User)authentication.getPrincipal();
        // System.out.println(authentication.getPrincipal());
        System.out.println(user.toString());

        // System.out.println(authentication.getAuthorities().toArray()[0]);
        String role = (String)authentication.getAuthorities().toArray()[0].toString();
        System.out.println(role);

        if(role.equals("ADMIN")){
            response.sendRedirect( request.getContextPath() + "/security_admin/home");
        }
        else if(role.equals("SELLER")){
            response.sendRedirect(request.getContextPath() + "/security_seller/home");
        }
        else if(role.equals("CUSTOMER")){
            response.sendRedirect(request.getContextPath() + "/security_customer/home");
        }        
    }    
}

파일명 MyLogoutSuccessHandler.java

package com.example.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

public class MyLogoutSuccessHandler implements LogoutSuccessHandler{

    @Override
    public void onLogoutSuccess(
            HttpServletRequest request, 
            HttpServletResponse response, 
            Authentication authentication)
            throws IOException, ServletException {
        
        response.sendRedirect( request.getContextPath() + "/security_home");
        
    }    
}
profile
당신을 한 줄로 소개해보세요

0개의 댓글

Powered by GraphCDN, the GraphQL CDN