시큐리티를 이용한 로그인 처리

세피·2021년 11월 12일
0

스프링

목록 보기
4/11
post-thumbnail

시큐리티를 이용한 로그인 처리

WebSecurityConfig.java

.formLogin()
// 로그인 처리 경로, form의 action과 일치시켜주자. login주소가 호출되면 시큐리티가 낚아채서 대신 로그인 진행해줌
.loginProcessingUrl("/login")

loginForm.jsp

 <form action="login" class="login" method="POST">
 <input type="text" name="username" id="Id" class="form-control" placeholder="아이디" autofocus required><BR>
        <input type="password" name="password" id="Pw" class="form-control" placeholder="비밀번호"  required><br>
         <p id="check" class="check">${login_msg}</p><br/>
        <input id="btn-Yes" class="btn btn-lg btn-primary btn-block" type="submit" value="로 그 인">
      </form>

시큐리티 흐름 먼저 보자

https://www.gunlog.dev/Spring%20Security

  • Authentication - 요청 시 입력 받은 사용자 ID, 패스워드와 같은 인증 요청 정보를 가지고 있다.
  • 1AuthenticationFilter - 시큐리티 관련 전처리를 위한 필터
  • 3AuthenticaitonManager - 사용자 비밀번호를 인증하는 역할을 담당한다.
  • 4AuthenticationProvider - AuthenticationManager에게 비밀번호 인증 기능을 제공한다.
  • 5UserDetailsService - UserDetails를 반환함
  • 6UserDetails - DB에서 가져온 사용자 정보(이름, 이메일, 전화번호)를 저장하기 위함.
  • SecurityContext - Authentication를 보관함

  1. UsernamePasswordAuthenticationFilter(AuthenticationFilter)HttpServletRequest에서 사용자가 전송한 아이디와 패스워드를 가로챈다.
  2. AuthenticationFilter는 인증용 객체 Authentication을 생성한다.
  3. AuthenticationFilter는 인증을 위해 AuthenticationManager에게 Authentication을 전달한다.
  4. AuthenticationManager는 실제 인증 기능이 수행을 위해 AuthenticationProvider에게 다시 Authentication을 전달한다.
  5. AuthenticationProviderUserDetailsService에게 조회할 username을 전달하여 인증을 위한 UserDetails(DB 사용자 정보) 객체를 요청한다.
  6. UserDetailsServiceAuthenticationProvider에게 전달 받은 username을 통해 UserDetails(DB 사용자 정보)를 찾는다.
  7. UserDetailsService는 username을 통해 찾은 UserDetails(DB 사용자 정보)를 반환한다.
  8. AuthenticationProviderAuthenticationUserDetails를 가지고 인증을 수행하여 인증에 성공 시 Authentication을 반환한다. (반환할 Authentication에는 부여된 권한, 인증 여부가 포함됨)
  9. AuthenticationManagerAuthenticationProvider을 통해 인증에 성공할 경우 전달 AuthenticationProvider을 통해 전달받은 Authentication을 반환한다.
  10. 인증이 최종적으로 완료되면 Authentication객체를 SecurityContextHolder에 담은 후 성공 시 AuthenticationSuccessHandler, 실패 시 AuthenticationFailureHandler를 실행한다.

나하하하하....

다시 내 언어로 정리란걸 해보자

  1. loginForm.jsp 에서 form action = "/login", method="POST" 로 username과 password를 보냄

    시큐리티를 적용하지 않았을땐 service 단에서 처리를 해줬었음 근데 지금은 시큐리티를 적용할거니까! 흐름을 고쳐먹어!

  2. WebSecurityConfig.java 안에 .loginProcessingUrl("/login") 가 위에거 낚아 챔 (컨트롤러 대신)

클라이언트가 로그인 요청 id랑pw 값 들고옴
AuthenticationFilter가 그 값을 가져감 -> Authentication(토큰) 객체 생성
인증을 위해 AuthenticationManager에게 Authentication 전달
AuthenticationManager는 실제 인증 기능이 수행을 위해 AuthenticationProvider에게 다시 Authentication을 전달한다.

  1. AuthenticationProvider는 UserDetailsService에게 조회할 username을 전달하여 인증을 위한 UserDetails(DB 사용자 정보) 객체를 요청한다. 어 그니까 2번에서 이제 service단으로 온다고

UserDetails : 사용자의 정보를 담는 인터페이스 시큐리티엔 시큐리티 session이 따로 존재함 (Security ContextHolder) 로그인 요청이 오면 시큐리티가 가져가서 실행시킴 흐름 완료되면 security session 생성 --> Authentication 타입의 객체 --> 이 안에는 user 정보가 있다. --> 이 user의 타입은 UserDetails 타입 객체임

PrincipalDetailsService.java

// AuthenticationProvider는 UserDetailsService에게 조회할 username을 전달하여 인증을 위한 UserDetails(DB 사용자 정보) 객체를 요청한다.
// .loginProcessingUrl("/login") 이 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어 있는 loadUserByUsername 함수가 실행
// method : loadUserByUsername : 유저 정보를 불러오는 메서드, CustomUserDetails 형으로 사용자의 정보를 가져옴

@Service
public class PrincipalDetailsService implements UserDetailsService {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private MainDao dao;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		logger.info("입력한 아이디 값 : " + username);
		// username은 loginForm에 있는 name = username을 뜻하는 것임 그러니까, 이름 확인 잘할것
		// 만약에 이름을 바꾸고 싶다면 HttpSecurity http 에서 .usernameParameter("바꾼 이름") 입력해줘야함
		MainDto user = dao.findId(username);
		return user;

	}
  1. 자 이제 DB인 UserDetails 로 가야함 (이게 DTO임을 늦게야 알았다.. useDetails)

MainDto.java

package com.spring.main.dto;

import java.util.ArrayList;
import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class MainDto implements UserDetails {

	private String member_id;
	private String pw;
	private String name;
	private String role;

	public String getMember_id() {
		return member_id;
	}

	public void setMember_id(String member_id) {
		this.member_id = member_id;
	}

	public String getPw() {
		return pw;
	}

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

	public String getName() {
		return name;
	}

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

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	

	// <method>
	// getAuthorities : 계정의 권한 목록 리턴
	// 리턴타입 : Collection<? extends GrantedAuthority>

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		ArrayList<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
        auth.add(new SimpleGrantedAuthority(role));
        return auth;
	}

		// dto.getRole(); // String이므로 위에처럼 타입 변환이 필요함

	// getPassword 계정의 비밀번호를 리턴
	@Override
	public String getPassword() {
		return pw;
	}

	// getUsername : 계정의 고유한 값을 리턴 *PK 값*
	@Override
	public String getUsername() {
		return member_id;
	}

	// isAccountNonExpired : 계정의 만료 여부 리턴 ( true일시 만료x )
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	// isAccountNonLocked : 계정의 잠김 여부 리턴 ( true일시 잠김x )

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	// isCredentialsNonExpired : 비밀번호 만료 여부 리턴 ( true일시 만료x )

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	// isEnabled : 계정의 활성화 여부 ( ture면 활성화 o )

	@Override
	public boolean isEnabled() {

		// 1년간 로그인 안한 계정 즉 휴면계정일때 사용

		return true;
	}

}

MainDao.java

@Mapper
public interface MainDao {
	public MainDto findId(String member_id);
}

Mapper.xml

<select id="findId" parameterType="String" resultType="com.spring.main.dto.MainDto">
	SELECT * FROM member2 WHERE member_id=#{member_id}
	</select>
profile
세피의 블로그입니다

0개의 댓글