티스토리 뷰

728x90
반응형

 

 

 

먼저, 로그인 페이지를 만들어줍니다.

컨트롤러에 로그인 페이지를 생성해주세요.

// Controller
@RequestMapping("/login")
public String login() throws Exception {
    return "login";
}

 

 

연결된 로그인 html파일에는 다음과 같이 "username"과 "password"가 있어야 합니다.

method는 무조건 post여야하구요!!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <form action="/login" method="post">
    	<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required><br>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password" required><br>
        <!-- input fields for username and password -->
    	<button type="submit">Login</button>
</form>
</body>
</html>

 

 

 

이제 로그인페이지를 통해 로그인한 사용자의 ID를 토대로 DB에서 사용자권한정보를 가져와야합니다.

이 부분은 spring security를 이용합니다.

spring security를 pom.xml에 추가해줍니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

 

 

반응형

 

그리고 DB 사용자정보 테이블에서 사용자ID를 토대로 사용자정보를 가져오는 UserService를 만들어놓습니다.

사용자가 로그인페이지에서 로그인 시, 로그인한 USER_ID를 토대로 권한을 가져오는 서비스입니다.

// ID -> 사용자정보 조회
public List<UserDTO> getUserInfo(String USER_ID)throws Exception {
    return UserDAO.getUserInfo(USER_ID);
}

 

 

이제 사용자가 로그인 시, 사용자권한정보를 가져오는 UserDetailsService를 만듭니다.

사용자가 로그인버튼을 누르면 loadUserByUsername이 실행됩니다.

저는 비밀번호없이 로그인하게끔 만들어놓았기에 비밀번호는 "1111"로 고정해놓았습니다.

userDetails = builder.username(userInfo.get(0).getUser_id()) <- 이부분에서 사용자권한정보를 가져오면 됩니다.

 

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import dto.UserDTO;
import service.UserService;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
	
	@Autowired
	private UserService userService;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		UserDetails userDetails = null;
		System.out.println(username); 
		List<UserDTO> userInfo;
		try {
			userInfo = userService.getUserInfo(username);
			PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
			
			org.springframework.security.core.userdetails.User.UserBuilder builder =
						org.springframework.security.core.userdetails.User.builder().passwordEncoder(encoder::encode);
					
			if (userInfo.size() > 0) {
				userDetails = builder.username(userInfo.get(0).getUser_id())
						.password("1111") // 비밀번호 없음
						.roles(userInfo.get(0).getAuth())
						.build();
			}else {
            	// 계정정보가 없는 경우
	            throw new UsernameNotFoundException("User not found with username: " + username);
	        }
		} catch (Exception e) {
			System.out.println(e);
			throw new UsernameNotFoundException("Exception occurred while loading user by username", e);
	    }
		
		return userDetails;
	}

}

 

 

728x90

 

마지막으로 spring security의 configuration을 만들어줍니다.

CORS설정 이라고 주석처리되어있는 부분을 삽입하지 않으면 로그인버튼을 눌러도 302에러가 뜨면서 계속 GET으로만 요청이 들어오더라구요. CORS 설정을 꼭 넣어주세요.

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

	//CORS 설정
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();

        config.setAllowCredentials(true);
        config.setAllowedOrigins(Arrays.asList("http://localhost:80"));
        config.setAllowedMethods(Arrays.asList("HEAD","POST","GET","DELETE","PUT"));
        config.setAllowedHeaders(Arrays.asList("*"));

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
	        .httpBasic().disable()
	        .cors().configurationSource(corsConfigurationSource())
	        .and()
            .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .defaultSuccessUrl("/", true) // 로그인 성공 시 "/"로 리다이렉트
                .and()
            .logout()
                .permitAll();
        http.csrf().disable();
        http.headers().frameOptions().disable();
        
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

 

 

 

이제 로그인페이지에서 로그인 버튼을 누르면, UserDetailsServiceImpl에서 출력해놓았던

System.out.println(username); <- 요부분이 콘솔창에 출력되고, 사용자권한별로 페이지접속이 가능해집니다.

 

이제 권한별 페이지접속 설정을 해봅니다.

SecurityConfig파일에서 페이지 접속을 설정하는 부분입니다.

권한별 URL을 설정해주면 됩니다.

   
.antMatchers("/login", "/css/**", "/js/**",  "/font/**", "/images/**").permitAll() // "/" 및 스태틱자원들의 경로는 모두에게 허용
    .antMatchers("/manage/**").hasRole("ADMIN") // ADMIN 권한 필요
    .anyRequest().authenticated() // 그 외의 리소스는 인증된 사용자만 허용

 

 

 

- 컨트롤러에서 사용자ID, 권한정보 가져오는 방법

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 사용자 ID
String USER_ID = authentication.getName();
// 권한정보
String Authority = authentication.getAuthorities();

 

 

 

로그아웃기능에 대해서는 아래 링크를 눌러주세요

 

[java] spring security 로그아웃기능 만들기 (+자동로그아웃)

https://domdom.tistory.com/660

 

[java] spring security 로그아웃기능 만들기 (+자동로그아웃)

예전에 spring security로 로그인, 사용자권한별 페이지접속에 대해서 글을 적은적이 있는데요. 이번에는 로그아웃 기능을 만들고, 아래와 같이 3가지 기능을 추가해보려고 합니다. 1. 로그아웃버튼

domdom.tistory.com

 

728x90
반응형
댓글