스프링 시큐리티

Structure of Knowledge·2021년 4월 4일
0

Spring MVC Exercise #2

목록 보기
6/6

참조문서: https://codevang.tistory.com/ & https://bin-repository.tistory.com/128?category=879445

  1. 라이브러리 추가
  2. 시큐리티 설정(xml 이용)
  3. 로그인 커스터마이징
  4. 회원 가입 시 달라진 점

회원 가입 시, 달라진 점

  • Member DTO로 전달된 비밀번호를 암호화한다.
  • 입력된 이메일로 인증 메일을 발송하고, 모든 정보를 회원 테이블에 저장한다.
  • 이 때, 인증 여부를 시큐리티에서 이용하는 Enabled 컬럼을 이용하여 인증 버튼을 클릭하면 enabled 값을 0에서 1로 변경해준다. ( 1은 enabled 체크에서 true로 나오는 값 )
//컨트롤러
@PostMapping("join.do")
public ModelAndView join(Member member) {
	int joinCode = service.join(member);
	if(joinCode == JOIN_F_EMAIL_EXIST) {
		//log.info(joinCode);
		return new ModelAndView("member/join","joinCode", joinCode);	// 회원가입 실패 메세지
	}else if(joinCode == JOIN_SUCCESS){
		return new ModelAndView("member/login","joinCode", joinCode);	// 회원가입 성공, 이메일 인증 요구 메세지
	}
	return null;
}
    
@GetMapping("joinConfirm")
public ModelAndView joinConfirm(Member member) {
	int joinCode = service.checkMailAuth(member);
	return new ModelAndView("member/login","joinCode",joinCode);	// 인증 성공, 또는 실패
}
@Service
@AllArgsConstructor
public class MemberServiceImpl implements MemberService {
	private MemberMapper mapperM;
	private BCryptPasswordEncoder bcryptPwdEncoder;
	private JavaMailSenderImpl mailSender;
	
	@Override
	public int join(Member member) {
		try{
			String encodedPwd = bcryptPwdEncoder.encode(member.getM_pwd());
			member.setM_pwd(encodedPwd);
			String emailAuth = sendAuthMail(member.getM_email());	// 인증메일 발송 
			member.setM_mailAuth(emailAuth);
			mapperM.insertMember(member);
			return JOIN_SUCCESS;
		}catch(DataAccessException dae) {
			System.out.println(dae);
			return JOIN_F_EMAIL_EXIST;
		}
	}
 
	private String sendAuthMail(String email) {
		//6자리 난수 인증번호 생성
        	String authKey = getKey(6);

        	//인증메일 보내기
        	try {
            		MailUtils sendMail = new MailUtils(mailSender);
            		sendMail.setSubject("회원가입 이메일 인증");
            		sendMail.setText(new StringBuffer().append("<h1>[이메일 인증]</h1>")
            			.append("<p>아래 링크를 클릭하시면 이메일 인증이 완료됩니다.</p>")
            			.append("<a href='http://localhost:8080/member/joinConfirm?m_email=")
            			.append(email)
            			.append("&m_mailAuth=")
            			.append(authKey)
            			.append("' target='_blenk'>이메일 인증 확인</a>")
            			.toString());
            		sendMail.setFrom("accForHibooks@gmail.com", "관리자");
            		sendMail.setTo(email);
            		sendMail.send();
       		 } catch (MessagingException e) {
            		e.printStackTrace();
        	} catch (UnsupportedEncodingException e) {
            		e.printStackTrace();
        	}
          	return authKey;
    	}
	
    	@Override
	public int checkMailAuth(Member member) {	// 이메일 인증시 계정 활성화
		Member memberChecked = mapperM.selectMemberInfo(member);
		String inputMailAuth = member.getM_mailAuth();
		String getMailAuth = memberChecked.getM_mailAuth();
		if(inputMailAuth.equals(getMailAuth)) {
			mapperM.updateEnabled(memberChecked);	// enabled 컬럼을 0 -> 1로 바꿈
			return MAIL_AUTH_SUCCESS;
		}else {
			return MAIL_AUTH_FAIL;
		}
	}
    
    	.............
        
}



로그인 과정 커스터 마이징

  • UserDetails 클래스는 시큐리티에서 인증과정에 필요한 정보를 담고 있는 객체이다.
  • UserDetailsService 클래스는 인증과정에서 UserDetails 객체를 인증 절차에 넘겨주는 객체이다.
  • UserDetails를 구현할 때, 기존의 회원 서비스에서 이용했던 Member DTO를 멤버변수로 사용하여 커스터마이징 하였다.
@SuppressWarnings("serial")
public class MemberDetails implements UserDetails {
	private Member member;
	
	public MemberDetails(Member member) {
		this.member = member;
	}
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		ArrayList<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
		authList.add(new SimpleGrantedAuthority(member.getM_auth()));
		return authList;
	}
	@Override
	public String getPassword() {
		return member.getM_pwd();
	}
	@Override
	public String getUsername() {
		return member.getM_email();
	}
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}
	@Override
	public boolean isEnabled() {
		return member.getEnabled()==1?true:false;
	}
	// 회원정보를 불러와야할 경우
	public Member getMember() {
		member.setM_pwd(null);
		return member;
	}
	public void setMember(Member member) {
		this.member = member;
	}
}
public class MemberDetailsService implements UserDetailsService {
	@Autowired
	private MemberMapper mapper;
	
	@Override
	public UserDetails loadUserByUsername(String m_email) throws UsernameNotFoundException {
		Member member = new Member();
		member.setM_email(m_email);
		member = mapper.selectMemberInfo(member);
		if(member == null) throw new UsernameNotFoundException("없는 이메일");
		MemberDetails user = new MemberDetails(member); 
		return user;
	}
}

Maven에 라이브러리 추가

<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-core</artifactId>
	<version>${spring.security.version}</version>
</dependency>		
<dependency>
	<groupId>org.springframework.security</groupId>
    	<artifactId>spring-security-web</artifactId>
    	<version>${spring.security.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-config</artifactId>
	<version>${spring.security.version}</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-taglibs</artifactId>
	<version>${spring.security.version}</version>
</dependency>

spring-context.xml 로 설정

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:security="http://www.springframework.org/schema/security"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security-4.2.xsd
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	
	<context:component-scan base-package="bit.hibooks.security"></context:component-scan>
	<!-- 암호화 객체 생성 -->	
    	<bean id="bcryptPwdEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
	<!-- 로그인 시 시큐리티에서 사용하는 서비스 객체(userDetailsService 클래스 커스터마이징) -->	
    	<bean id="memberDetailsService" class="bit.hibooks.security.MemberDetailsService"></bean>
	<!-- 로그인 실패시 시큐리티에서 사용하는 객체  -->	
    	<bean id="loginFailHandler" class="bit.hibooks.security.LoginFailHandler"></bean>
	<!-- csrf 제외 url 설정 -->	
	<!-- <bean id="csrfSecurityRequestMatcher" class="bit.hibooks.security.CsrfSecurityRequestMatcher"/> -->
	<!-- 시큐리티 설정 -->	
    	<security:http>
		<security:csrf disabled="true"/>	
		<security:intercept-url pattern="/" access="permitAll"/>
		<security:intercept-url pattern="/member/moveMyInfo.do" access="hasRole('ROLE_USER')"/>
		<security:intercept-url pattern="/wishList/*" access="hasRole('ROLE_USER')"/>
		<security:intercept-url pattern="/purchase/checkout.do" access="hasRole('ROLE_USER')"/>
		<security:intercept-url pattern="/purchase/placeorder.do" access="hasRole('ROLE_USER')"/>
		<security:intercept-url pattern="/purchase/orderComplete.do" access="hasRole('ROLE_USER')"/>
		<security:intercept-url pattern="/boardq/write.do" access="hasRole('ROLE_USER')"/>
		<security:form-login login-page="/member/login.do"
						username-parameter="m_email"
						password-parameter="m_pwd"
						login-processing-url="/member/login.do"
						always-use-default-target="true"
						default-target-url="/" 
						authentication-failure-handler-ref="loginFailHandler"/>
		<security:access-denied-handler error-page="/"/>
		<security:logout logout-url="/member/logout.do"
					logout-success-url="/" />
			
							
		<!-- max session setting -->
		<security:session-management invalid-session-url="/">
	            	<security:concurrency-control max-sessions="1"
						  expired-url="/"
						  error-if-maximum-exceeded="true" />
		</security:session-management>
	  
	    	<!-- remember-me -->
	        	<security:remember-me user-service-ref="memberDetailsService" remember-me-parameter="remember-me"
	        						token-validity-seconds="600000" />
	        						
	</security:http>
		
	<!-- get UserInfo by MyBatis from DB -->
    	<!-- 임의의 계정 등록(관리자), 데이터베이스에 저장된 정보 참조 -->	
	<security:authentication-manager>
		<security:authentication-provider>
			<security:user-service>
				<security:user name="admin" password="admin" authorities="ROLE_ADMIN" />
			</security:user-service>
		</security:authentication-provider>
		<security:authentication-provider user-service-ref="memberDetailsService">
			<security:password-encoder hash="bcrypt"></security:password-encoder>
			</security:authentication-provider>
	</security:authentication-manager>
</beans>
profile
객체와 제어, 비전공자 개발자 되기

0개의 댓글