Spring Security

Spring-boot + security 설정 -1

스마트큐브 2019. 9. 7. 18:53

가장 기본적인 형태의 스프링 시큐리티 설정에서 부터 내가 원하는 기능으로 바꿀때까지 

하나씩 기록을 목적으로 이렇게 또 적어둔다. 

 

일단 스프링 스타터로 아무것도 안해도 이렇게 화면이 뜬다. 

초기 화면 

'순간 머지?' 암호랑 패쓰는 머지?!! 

그랬다가 좀 찾아보니 

콘솔에 이렇게 뜨길래 다시 또  ' 그럼 id ? '  하면 몇 개 트라이해보니  "user" 임을 깨닫게 되었다. 

 

이제 그럼 내가 만든 사용자 DB 로 로그인하려면 어떻게 하지? 

음..이제 또 구글신공 시작! 
https://a1010100z.tistory.com/entry/Spring-Spring-security-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85%EB%B6%80%ED%84%B0-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EA%B9%8C%EC%A7%80-Spring-boot-Gradle-MyBatis-MySQL

일단 위 글이 괜찮아 보여서 읽기 시작 

(10분 후 ) 음... 나의 의식의 흐름과 다른 흐름이라 그런지.. 잘 모르것다.. 다시 검색 시작 

https://wedul.site/170

http://progtrend.blogspot.com/2018/07/spring-boot-security.html

 

위 글이 도움이 젤 많이 됐다. 

 

1.  인증프로바이더 설정 (= 내가 정의한 db 로  id/pass 매칭 체크 어떻게 할껀지?)

package com.cube.login.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import com.cube.login.dao.LoginMapper;
import com.cube.model.UserVo;
  
@Component
public class AuthProvider implements AuthenticationProvider  {
    
    @Autowired
    LoginMapper loginMapper;
    
    @Autowired
    PasswordEncoder pwdEncoder;
    
 
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String id = authentication.getName();
        
        UserVo user = loginMapper.getUser(id);
        // 유저 없는경우 
        if (null == user ) {
            return null;
        }
        // 비번 불일치
        if (!pwdEncoder.matches(authentication.getCredentials().toString(), user.getPassword())) {
            throw new BadCredentialsException("Wrong password");
        }
        
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        
        grantedAuthorityList.add(new SimpleGrantedAuthority(user.getAuth()));         
 
        // 로그인 성공시 로그인 사용자 정보 반환
        return new UsernamePasswordAuthenticationToken(user, null, grantedAuthorityList);
    }
    
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
 
}

 

2. SpringSecurity Config 클래스 추가 

package com.cube.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.cube.login.service.AuthFailureHandler;
import com.cube.login.service.AuthProvider;
import com.cube.login.service.AuthSuccessHandler;

 
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
   
   @Autowired
   AuthProvider authProvider;
   
   @Autowired
   AuthFailureHandler authFailureHandler;

   @Autowired
   AuthSuccessHandler authSuccessHandler;

   @Override
   public void configure(WebSecurity web) throws Exception {
       // 허용되어야 할 경로들
       web.ignoring().antMatchers("/resources/**", 
                                  "/dist/**",
                                  "/css/**",
                                  "/font-awesome/**",
                                  "/fonts/**",
                                  "/img/**",
                                  "/js/**"); 
   }
   
   @Override
   protected void configure(HttpSecurity http) throws Exception {

       // 로그인 설정
       http.authorizeRequests()
       	   .antMatchers("/", "/user/login","/user/admin", "/error**").permitAll()
           // ROLE_USER, ROLE_ADMIN으로 권한 분리 유알엘 정의           
           .antMatchers("/**").access("ROLE_USER")
           .antMatchers("/**").access("ROLE_ADMIN")
           .antMatchers("/admin/**").access("ROLE_ADMIN")
           .antMatchers("/**").authenticated();
       http
           // 로그인 페이지 및 성공 url, handler 그리고 로그인 시 사용되는 id, password 파라미터 정의
           .formLogin()
           .loginPage("/user/login")
           .loginProcessingUrl("/authenticate")
           .defaultSuccessUrl("/")     
           .usernameParameter("id_user")
           .passwordParameter("password");
       http    
           // 로그아웃 관련 설정
           .logout().logoutRequestMatcher(new AntPathRequestMatcher("/user/logout"))
           .logoutSuccessUrl("/")
           .invalidateHttpSession(true)       
        .and()
          	.csrf()
          	.csrfTokenRepository(new CookieCsrfTokenRepository())
        .and()
           // 로그인 프로세스가 진행될 provider
           .authenticationProvider(authProvider);
   }

}

 

3. 로그인 JSP 페이지 

: csrf 문제인지 첨에 모르고 무한 403 에러를 만났다 ㅠㅠ. 

JSP 로 하려면 hidden  ${_csrf.parameterName} 에 값을 같이 post 로 쏴줘야 한다. 

<form class="m-t" role="form" action="/authenticate" method="POST">
<div class="form-group">
<input type="text" name="id_user" class="form-control" placeholder="Username" required="">
</div>
<div class="form-group">
<input type="password" name="password" class="form-control" placeholder="Password" required="">
</div>
<button type="submit" class="btn btn-primary block full-width m-b">Login</button>

<a href="#"><small>Forgot password?</small></a>
<p class="text-muted text-center"><small>Do not have an account?</small></p>
<a class="btn btn-sm btn-white btn-block" href="register.html">Create an account</a>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>

 

csrf 와 관련한 건 

https://reiphiel.tistory.com/entry/spring-security-csrf

위 링크가 설명이 젤 이해가 쉬웠다. 

그런데 typthymeleaf 를 쓰면 자동으로 hidden 으로 심어 준다고 하니.. 써봐야겠다.