[SpringBoot] spring legacy에서 spring boot로 변환 - 2. 회원가입/로그인/로그아웃 (spring security)

HodooHa·2024년 7월 13일

spring boot에서는 spring security를 적용하여 인증 및 인가를 구현했다.

우선 메인화면인 홈화면과 날씨는 하기와 같이 모든 접근을 허용하고자 한다.

화면

[메인화면]

[날씨]

'호두스케쥴러'의 핵심 기능인 [일정]과 [다이어리]는 접근 시 하기와 같은 로그인 화면이 뜨고 로그인을 한 유저에게만 접근을 허용한다.

[일정/다이어리 메뉴 선택 시 -> 로그인 화면]

[일정 (로그인 후)]

[다이어리 (로그인 후)]

또한 유저의 role은 2가지가 있는데 모든 권한을 가지고 있는 ADMIN(관리자)와 관리자 권한이 없이 사용자 권한을 가지는 MEMBER(사용자)가 있다.

관리자 계정으로 로그인 시 홈화면에는 '관리자페이지'로 이동할 수 있는 링크가 뜨고 클릭 시 관리자 페이지로 넘어간다.

[홈 - ADMIN]

[관리자페이지 - ADMIN]

사용자 계정으로 로그인 시 홈화면에는 '마이페이지'로 이동할 수 있는 링크가 뜨고 클릭 시 마이페이지로 넘어간다.

[홈 - MEMBER]

[마이페이지 - MEMBER]

만약, 사용자가 URL로 관리자 페이지 접근을 시도하면 하기와 같이 error페이지가 나온다.


소스코드

이제 소스코드를 보겠다.

제일 먼저 spring security 설정을 하기와 같이 했다.

[SpringSecurityConfig.java]

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;


@EnableWebSecurity
@Configuration
public class SpringSecurityConfig {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public WebSecurityCustomizer configure() {

        return (web) -> web.ignoring().requestMatchers(
                "/css/**", "/js/**", "/img/**", "/error/**", "/favicon.ico", "/common/**"
        );
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http.csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .requestMatchers("/diary/**").authenticated() // 권한확인
                        .requestMatchers("/task/**").authenticated()
                        .anyRequest().permitAll()
                )

                .formLogin(form -> form
                        .loginPage("/user/login")
                        .loginProcessingUrl("/user/login")
                        .permitAll()
                        .usernameParameter("username")
                        .passwordParameter("password")
                        .defaultSuccessUrl("/", true)
                        .failureForwardUrl("/error/error")

                ).logout(logout -> logout
                        .logoutRequestMatcher(new AntPathRequestMatcher("/user/logout"))
                        .deleteCookies("JSESSIONID")
                        .invalidateHttpSession(true)
                        .logoutSuccessUrl("/"))

                .exceptionHandling((exception) -> exception.accessDeniedPage("/error/error"));
        return http.build();


    }

}

[UserController.java]

import com.multi.hodooScheduler.user.model.dto.UserDTO;
import com.multi.hodooScheduler.user.service.UserService;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@SessionAttributes("loginUser")
@Controller
@RequestMapping("/user")
public class UserController {

	private UserService userService;

	@Autowired
	public UserController(UserService userService) {
		super();
		this.userService = userService;
	}

	@RequestMapping("/mypage")
	public String mypage(){
		return "user/userPage";
	}

	@GetMapping("/login")
	public void loginPage(){

	}

	@PostMapping("/login")
	public String loginUser(UserDTO userDTO, Model model, HttpSession session) {

		String page = "redirect:/";
		System.out.println(userDTO);
		try {
			UserDTO loginDTO = userService.loginUser(userDTO);
			model.addAttribute("loginUser", loginDTO);
			session.setAttribute("msg", "로그인 성공!");
		} catch (Exception e) {
			page = "common/errorPage";
			session.setAttribute("msg", "로그인 실패!");
			e.printStackTrace();
		}

		return page;
	}

	@GetMapping("/register")
	public String register() {

		return "user/registerform";

	}

	@PostMapping("/register")
	public String insertUser(UserDTO userDTO, Model model, HttpSession session) {

		String page = "";
		try {
			int result = userService.insertUser(userDTO);
			if (result > 0) {
				session.setAttribute("msg", "회원가입 성공!");
				page = "user/login";
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			page = "common/errorPage";
		}

		return page;
	}

	@RequestMapping("/logout")
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:/";
	}

	@RequestMapping("/idCheck.do")
	@ResponseBody
	public int idCheck(UserDTO userDTO) { // 아이디 중복체크!
		
		System.out.println(userDTO);
		int result = 0;
		try {
			UserDTO checkId = userService.idCheck(userDTO);
			if(checkId != null) {
				result = 1;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
		return result;
	}

}

[UserService.java]

import com.multi.hodooScheduler.user.model.dto.UserDTO;

public interface UserService {
	
	UserDTO loginUser(UserDTO userDTO) throws Exception;

	int insertUser(UserDTO userDTO) throws Exception;

	UserDTO idCheck(UserDTO userDTO) throws Exception;

	UserDTO findUserById(String userId) throws Exception;
}

[UserServiceImpl.java]

import com.multi.hodooScheduler.user.model.dao.UserDAO;
import com.multi.hodooScheduler.user.model.dto.UserDTO;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

	private SqlSessionTemplate sqlSession;
	private UserDAO userDAO;
	private BCryptPasswordEncoder bCryptPasswordEncoder;

	@Autowired
	public UserServiceImpl(SqlSessionTemplate sqlSession, UserDAO userDAO,
			BCryptPasswordEncoder bCryptPasswordEncoder) {
		super();
		this.sqlSession = sqlSession;
		this.userDAO = userDAO;
		this.bCryptPasswordEncoder = bCryptPasswordEncoder;
	}

	@Override
	public UserDTO loginUser(UserDTO userDTO) throws Exception {

		String encpw = userDAO.selectEncryptedPwd(sqlSession, userDTO);
		if (!bCryptPasswordEncoder.matches(userDTO.getPw(), encpw)) {
			throw new Exception("패스워드 불일치, 로그인 실패");
		}
		
		UserDTO loginDto = userDAO.loginUser(sqlSession, userDTO);
		if (loginDto == null) {
			throw new Exception("loginUser 정보 확인, 로그인 실패");
		}

		return loginDto;
	}

	@Override
	public UserDTO findUserById(String userId) throws Exception {
		UserDTO userDTO = userDAO.findUserById(sqlSession, userId);
		if(userDTO == null){
			throw new Exception("일치하는 회원이 없습니다.");
		}

		return userDTO;
	}

	@Override
	public int insertUser(UserDTO userDTO) throws Exception {

		String encpw = bCryptPasswordEncoder.encode(userDTO.getPw());

		int result = userDAO.insertUser(sqlSession, userDTO);


		return result;
	}

	@Override
	public UserDTO idCheck(UserDTO userDTO) throws Exception {
		
	
		UserDTO loginDto = userDAO.loginUser(sqlSession, userDTO);
	
		return loginDto;
	}

}

[UserDAO.java]

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;

import com.multi.hodooScheduler.user.model.dto.UserDTO;

@Repository
public class UserDAO {

	public UserDTO loginUser(SqlSessionTemplate sqlSession, UserDTO userDTO) {
		
		return sqlSession.selectOne("userMapper.selectUser", userDTO);
	}

	public int insertUser(SqlSessionTemplate sqlSession, UserDTO userDTO) {
		
		return sqlSession.insert("userMapper.insertUser", userDTO);
	}

	public String selectEncryptedPwd(SqlSessionTemplate sqlSession, UserDTO userDTO) {
		
		return sqlSession.selectOne("userMapper.selectEncryptedPwd", userDTO);
	}

	public UserDTO findUserById(SqlSessionTemplate sqlSession, String userId){
		return sqlSession.selectOne("userMapper.selectUserById", userId);
	}


}

[userMapper.xml]

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="userMapper">
	<resultMap type="userDTO" id="userResultSet">
		<!-- 언더바가 들어가는 쿼리문에 한하여 매핑을 해줘야함 -->
		<id property="userId" column="user_id" />
		<result property="pw" column="pw" />
		<result property="name" column="name" />
		<result property="phone" column="phone" />
		<result property="createdDate" column="create_date" />
		<result property="isDeleted" column="isdeleted" />
		<result property="delDate" column="del_date" />
		<collection property="authList" resultMap="authMap" />
	</resultMap>

	<resultMap type="AuthDTO" id="authMap">
		<result property="authorityCode" column="authority_code" />
		<result property="authorityName" column="authority_name" />
		<result property="authority" column="authority" />
	</resultMap>

	<select id="selectUser" parameterType="userDTO"
		resultMap="userResultSet">
		SELECT *
		FROM USER u left join user_authority auth on u.authority_code = auth.authority_code
		WHERE user_id = #{userId}
	</select>

	<select id="selectUserById"
			resultMap="userResultSet">
		SELECT *
		FROM USER u left join user_authority auth on u.authority_code = auth.authority_code
		WHERE user_id = #{userId}
	</select>

	<select id="selectEncryptedPwd" parameterType="userDTO"
		resultType="java.lang.String">
		SELECT
		PW
		FROM USER
		WHERE user_id = #{ userId }
	</select>

	<select id="selectTaskList" parameterType="userDTO">
		SELECT *
		FROM TASK
		WHERE user_id = #{ userId}
	</select>

	<insert id="insertUser" parameterType="userDTO">

		INSERT
		INTO USER
		(user_id,
		pw, name, phone)
		VALUES (#{ userId }
		, #{ pw }
		, #{ name }
		, #{ phone })

	</insert>

</mapper>

[UserDTO.java]

import java.sql.Date;
import java.util.List;

public class UserDTO {

	private String userId;
	private String pw;
	private String name;
	private String phone;
	private Date createdDate;
	private String isDeleted;
	private Date delDate;
	private int authorityCode;
	private List<AuthDTO> authList;

	public List<AuthDTO> getAuthList() {
		return authList;
	}

	public void setAuthList(List<AuthDTO> authList) {
		this.authList = authList;
	}

	public UserDTO() {

	}

	public UserDTO(String userId){
		this.userId = userId;
	}

	public int getAuthorityCode() {
		return authorityCode;
	}

	public void setAuthorityCode(int authorityCode) {
		this.authorityCode = authorityCode;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getPw() {
		return pw;
	}

	public void setPw(String pw) {
		this.pw = pw;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	public String getIsDeleted() {
		return isDeleted;
	}

	public void setIsDeleted(String isDeleted) {
		this.isDeleted = isDeleted;
	}

	public Date getDelDate() {
		return delDate;
	}

	public void setDelDate(Date delDate) {
		this.delDate = delDate;
	}

	@Override
	public String toString() {
		return "UserDTO{" +
				"userId='" + userId + '\'' +
				", pw='" + pw + '\'' +
				", name='" + name + '\'' +
				", phone='" + phone + '\'' +
				", createdDate=" + createdDate +
				", isDeleted='" + isDeleted + '\'' +
				", delDate=" + delDate +
				", authorityCode=" + authorityCode +
				", authList=" + authList +
				'}';
	}
}

[AuthDTO.java]

public class AuthDTO {
    private int authorityCode;
    private String authorityName;
    private String authority;

    public AuthDTO() {
    }

    public AuthDTO(int authorityCode, String authorityName, String authority) {
        this.authorityCode = authorityCode;
        this.authorityName = authorityName;
        this.authority = authority;
    }

    public int getAuthorityCode() {
        return authorityCode;
    }

    public void setAuthorityCode(int authorityCode) {
        this.authorityCode = authorityCode;
    }

    public String getAuthorityName() {
        return authorityName;
    }

    public void setAuthorityName(String authorityName) {
        this.authorityName = authorityName;
    }

    public String getAuthority() {
        return authority;
    }

    public void setAuthority(String authority) {
        this.authority = authority;
    }
}

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

profile
성장하는 개발자, 하지은입니다.

0개의 댓글