728x90
반응형
[Springboot] 32. 사용자 비밀번호 암호화 처리
1. SpringSecurityCrypto 의존성 추가
*Spring Security Crypto란?
-build.gradle 코드 수정
// 암호화
implementation 'org.springframework.security:spring-security-crypto'
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.2.8'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
// 의존성 추가
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation group: 'org.glassfish.web', name: 'jakarta.servlet.jsp.jstl', version: '3.0.0'
// TODO - check
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
// 암호화
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
2. 사용자 비밀번호 암호화 처리
(1) WebMvcConfig
@Bean // IOC 대상
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
package com.tenco.bank.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.tenco.bank.handler.AuthIntercepter;
import lombok.RequiredArgsConstructor;
@Configuration // <-- 하나의 클래스를 IOC 하고 싶다면 사용
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired // DI
private final AuthIntercepter authIntercepter;
// @RequiredArgsConstructor <-- 생성자 대신 사용 가능!
// 우리가 만든 AuthIntercepter를 등록해야 한다.
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authIntercepter)
.addPathPatterns("/account/**")
.addPathPatterns("/auth/**");
}
@Bean // IOC 대상
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
(2) UserService 구상
package com.tenco.bank.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.tenco.bank.dto.SignInDTO;
import com.tenco.bank.dto.SignUpDTO;
import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.handler.exception.RedirectException;
import com.tenco.bank.repository.interfaces.UserRepository;
import com.tenco.bank.repository.model.User;
import lombok.RequiredArgsConstructor;
@Service // IoC 대상( 싱글톤으로 관리)
@RequiredArgsConstructor
public class UserService {
@Autowired
private final UserRepository userRepository;
@Autowired
private final PasswordEncoder passwordEncoder;
/**
* 회원 등록 서비스 기능
* 트랜잭션 처리
* @param dto
*/
@Transactional // 트랜잭션 처리는 반드시 습관화
public void createUser(SignUpDTO dto) {
int result = 0;
try {
// 코드 추가 부분
// 회원 가입 요청 시, 사용자가 던진 비밀번호 값을 암호화처리 해야함
String hashpwd = passwordEncoder.encode(dto.getPassword());
System.out.println("암호화 확인: "+hashpwd);
dto.setPassword(hashpwd);
result = userRepository.insert(dto.toUser());
} catch (DataAccessException e) {
throw new DataDeliveryException("중복 이름을 사용할 수 없습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
} catch (Exception e) {
throw new RedirectException("알 수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
}
if(result != 1) {
throw new DataDeliveryException("회원가입 실패", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public User readUser(SignInDTO dto) {
// 유효성 검사는 Controller 에서 먼저 하자.
User userEntity = null; // 지역 변수 선언
// 기능 수정
// username만 가지고 select 처리하기
// 2가지의 경우의 수 --> 있거나. 없거나
// 객체 안에 사용자의 password가 존재한다. (암호화된 값)
// passworEncoder 안에 매치하는 메서드 존재 => matches 메서드
try {
userEntity = userRepository.findByUsernameAndPassword(dto.getUsername(), dto.getPassword());
} catch (DataAccessException e) {
throw new DataDeliveryException("잘못된 처리 입니다.", HttpStatus.INTERNAL_SERVER_ERROR);
} catch (Exception e) {
throw new RedirectException("알수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
}
if(userEntity == null) {
throw new DataDeliveryException("아이디 혹은 비밀번호가 틀렸습니다.", HttpStatus.BAD_REQUEST);
}
return userEntity;
}
3. 비밀번호-암호화된 비밀번호 매칭을 위한 메서드
(1) xml / repository 수정
public User findByUsername(@Param("username") String username);
<select id="findByUsername" resultType="com.tenco.bank.repository.model.User" >
select * from user_tb where username = #{username}
</select>
(2) UserService 수정
public User readUser(SignInDTO dto) {
// 유효성 검사는 Controller 에서 먼저 하자.
User userEntity = null; // 지역 변수 선언
// 기능 수정
// username만 가지고 select 처리하기
// 2가지의 경우의 수 --> 있거나. 없거나
// 객체 안에 사용자의 password가 존재한다. (암호화된 값)
// passworEncoder 안에 매치하는 메서드 존재 => matches 메서드
try {
userEntity = userRepository.findByUsername(dto.getUsername());
} catch (DataAccessException e) {
throw new DataDeliveryException("잘못된 처리 입니다.", HttpStatus.INTERNAL_SERVER_ERROR);
} catch (Exception e) {
throw new RedirectException("알수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
}
if(userEntity == null) {
throw new DataDeliveryException("아이디 혹은 비밀번호가 틀렸습니다.", HttpStatus.BAD_REQUEST);
}
boolean isPwdMatched = passwordEncoder.matches(dto.getPassword(), userEntity.getPassword());
if(isPwdMatched == false) {
throw new DataDeliveryException("비밀번호가 틀렸습니다.", HttpStatus.BAD_REQUEST);
}
return userEntity;
}
728x90
반응형
'Springboot' 카테고리의 다른 글
[Springboot] 34. 파일 업로드(2단계-DTO, Service, JSP 수정) (0) | 2024.08.13 |
---|---|
[Springboot] 33. 파일 업로드(1단계-멀티 파트란?) (0) | 2024.08.13 |
[Springboot] 31. DB 마이그레이션 (H2->MySQL) (0) | 2024.08.13 |
[Springboot] 30. Intercepter 활용 (인증검사 공통 처리) (0) | 2024.08.13 |
[Springboot] 29. 계좌 상세 보기 기능(5단계-계좌 목록 페이징 처리) (0) | 2024.08.12 |