java

์Šคํ”„๋ง security ์„ค์ •ํ•˜๊ธฐ

dev_summer 2021. 2. 27. 14:24
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new SessionIntercepter())
			.addPathPatterns("/user/profile/**")
			.addPathPatterns("/post/write/**")
			.addPathPatterns("/post/update/**")
			.addPathPatterns("/post/delete/**");
		
			// addExcludePatterns() ์ œ์™ธ ์‹œํ‚ฌ ๋•Œ ์‚ฌ์šฉ!!
	}
	

 

 

 

1. ์‹œํ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•œ ์‚ญ์ œํŒŒ์ผ

- WebConfig.java

์ธํ„ฐ์…‰ํ„ฐ ์‚ฌ์šฉ ์•ˆํ•จ

 

 

 

- SessionIntercepter

ํ†ต์งธ๋กœ ๋‚ ๋ฆผ, ์ธํ„ฐ์…‰ํ„ฐ ์ž‘๋™ ์•ˆํ•จ

 

- pom.xml์˜ security์ฃผ์„ ํ’€๊ธฐ

 

 

๋น„๋ฐ€๋ฒˆํ˜ธ

 

๊ธฐ๋ณธ์ ์œผ๋กœ user, ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์ฝ˜์†”์ฐฝ์— ์žˆ๋Š”๊ฒƒ ๋ณต๋ถ™ ํ•˜๋ฉด ๋‚˜์˜ด!

๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธ์…˜์„ ์—ด๋ฉด ์ œ๊ณต๋˜๋Š” ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์ปจํ…์ŠคํŠธ ์„ธ์…˜

์ด๊ณณ์— ์–ด์„ ํ‹ฐ์ผ€์ด์…˜์ด ๋“ค์–ด๊ฐ„๋‹ค.

 

 

 

2. SecurityConfig.java ์ƒ์„ฑ

 

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // ์ง„์ž…๋˜๊ธฐ ์ง์ „์— ๋ฉ”๋ชจ๋ฆฌ์— ๋„์šธ ๊ฒƒ ์ด๋‹ค.
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Override
	protected void configure(HttpSecurity http) throws Exception { //๋ชจ๋“  ์š”์ฒญ์„ ๋ฐ›๋Š”๋‹ค. 

	    http.csrf().disable();

		http.authorizeRequests()
			.antMatchers("/user/profile/**","/post/write/**","/post/update/**","/post/delete/**","/post/detail/**").authenticated()
			.anyRequest().permitAll()
		.and() //์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ํผ ๋กœ๊ทธ์ธ์ด ์•„๋‹ˆ๋‹ค. ์›น์—์„œ๋Š” ํผ ๋กœ๊ทธ์ธ๋ฐฉ์‹์„ ๋งŽ์ด ์“ด๋‹ค.
			.formLogin()
			.loginPage("/user/login") //๊ทธ๋ƒฅ ์ฃผ์†Œ๋กœ ๊ฐ€๊ณ ์‹ถ์œผ๋ฉด loginProcessingUrl()๋กœ ๊ฐ€๋ฉด ๋˜๊ณ , ๊ทธ ์ „์— ๋ฌด์–ธ๊ฐˆ ์ˆ˜ํ–‰ํ•˜๊ณ ์‹ถ์œผ๋ฉดsuccessHandler์„ ์‚ฌ์šฉํ•˜์—ฌ new ํ• ์ˆ˜ ์žˆ๋‹ค.
            .loginProcessingUrl("/user/login") // POST๋งŒ ๋‚š์•„ ์ฑ”			
            .successHandler(new AuthenticationSuccessHandler() {
				@Override // authentication์— ๋‚˜์˜ ์ธ์ฆ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด๊ฐ€ ์žˆ๋‹ค.
				public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
						Authentication authentication) throws IOException, ServletException {
					// ๊ทธ ์ „์˜ user์˜ ์ •๋ณด๋ฅผ ๋ณด๊ณ  ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ, ํ•„ํ„ฐ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
					response.sendRedirect("/");
				}
			});
	}
}

 

 

package com.cos.blog.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // ์ง„์ž…๋˜๊ธฐ ์ง์ „์— ๋ฉ”๋ชจ๋ฆฌ์— ๋„์šธ ๊ฒƒ ์ด๋‹ค.
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Override
	protected void configure(HttpSecurity http) throws Exception { //๋ชจ๋“  ์š”์ฒญ์„ ๋ฐ›๋Š”๋‹ค. 
	    http.csrf().disable();

		http.authorizeRequests()
			.antMatchers("/user/profile/**","/post/write/**","/post/update/**","/post/delete/**","/post/detail/**").authenticated()
			.anyRequest().permitAll()
		.and() //์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ํผ ๋กœ๊ทธ์ธ์ด ์•„๋‹ˆ๋‹ค. ์›น์—์„œ๋Š” ํผ ๋กœ๊ทธ์ธ๋ฐฉ์‹์„ ๋งŽ์ด ์“ด๋‹ค.
			.formLogin()
			.loginPage("/user/login") // ๊ทธ๋ƒฅ ์ฃผ์†Œ๋กœ ๊ฐ€๊ณ ์‹ถ์œผ๋ฉด defaultSuccessUrl()๋กœ ๊ฐ€๋ฉด ๋˜๊ณ , ๊ทธ ์ „์— ๋ฌด์–ธ๊ฐˆ ์ˆ˜ํ–‰ํ•˜๊ณ ์‹ถ์œผ๋ฉดsuccessHandler์„ ์‚ฌ์šฉํ•˜์—ฌ new ํ• ์ˆ˜ ์žˆ๋‹ค.
			.loginProcessingUrl("/user/login") // POST๋งŒ ๋‚š์•„ ์ฑ”
			.defaultSuccessUrl("/");// successHamdler์‚ฌ์šฉ ๊ฐ€๋Šฅ 
	}
}

์ด๋•Œ๊นŒ์ง€ ํ•˜๋ฉด userdetail์ด ์—†๊ธฐ๋•Œ๋ฌธ์— ๋‚š์•„ ์ฑ„์งˆ ๋ชปํ•œ๋‹ค.

 

detail์„ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„ํ•˜๋Š” ์ž‘์—…์„ ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

 

 

 

 

 

3. MyUserDetailService์ƒ์„ฑ(detailservice๋ฅผ ์ƒ์†๋ฐ›์•„)

์œ ์ €๋„ค์ž„ ํŒจ์Šค์›Œ๋“œํ•„ํ„ฐ๊ฐ€ ์ž‘๋™ํ•˜๋ฉด์„œ ๋งŒ๋“  ํ† ํฐ์„ ์ „๋‹ฌ ๋ฐ›๋Š”๋‹ค.

- MyUserDetailService.java์ƒ์„ฑ

package com.cos.blog.service;

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.stereotype.Service;

import com.cos.blog.model.user.User;
import com.cos.blog.repository.UserRepository;

@Service
public class MyUserDetailService implements UserDetailsService{
	
	@Autowired
	private UserRepository userRepository;
	
	@Override // ํŒจ์Šค์›Œ๋“œ๋Š” ๊ฐ„์งํ•˜๊ณ  ์žˆ๊ณ  ์œ ์ €๋„ค์ž„๋งŒ ์ „๋‹ฌ ํ•ด์ค€๋‹ค.
	//์œ ์ €ํ”„๋กœ๋ฐ”์ด๋”๋Š” ์œ ์ €๋””ํ…Œ์ผ์„ ๋งŒ๋“ ๋‹ค. 
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		System.out.println("username : "+username);
		User user = userRepository.authentication(username);
		if (user==null) {
			throw new UsernameNotFoundException("ํ•ด๋‹น ์œ ์ €๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ");
		}
		return user;
	}
	
}

 

 

๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋˜ ์œ ์ € ๋ชจ๋ธ์€ ์œ ์ €๋””ํ…Œ์ผ์Šค๋ฅผ ์ž„ํ”Œ๋ฆฌ๋จผํŠธํ•ด์•ผํ•œ๋‹ค.

 

 

-User.java ์ˆ˜์ • ( implements UserDetails )

package com.cos.blog.model.user;

import java.sql.Timestamp;
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;

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

// MaBatis์—์„œ ResultType์œผ๋กœ ๋‹ด์„ ๋•Œ ์ƒ์„ฑ์ž ํ˜น์€ Setter์ค‘ ๋ฌด์—‡์ด ํ˜ธ์ถœ๋˜๋Š”์ง€ ํ™•์ธ ํ›„ Lombok ๋ณ€๊ฒฝ
@Data
@NoArgsConstructor
public class User implements UserDetails{
	private int id;
	private String username;
	private String password;
	private String email;
	private String profile;
	private String role; // USER,MANAGER,ADMIN
	private Timestamp createDate;
	
	@Builder
	public User(String username, String password, String email, String profile, String role) {
		super();
		this.username = username;
		this.password = password;
		this.email = email;
		this.profile = profile;
		this.role = role;
	}
	
    // username๊ณผ password์˜ getter๋„ ๋งŒ๋“ค์–ด์ ธ์•ผ ํ•˜๋Š”๋ฐ
    // ์šฐ๋ฆฌ๋Š” ํ•„๋“œ๋ช…์„ username๊ณผ password๋กœ ๋งŒ๋“ค์—ˆ๊ณ  lombok ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ๋†”์„œ
    // ์•ˆ๋งŒ๋“ค์–ด๋„๋œ๋‹ค.
	
	// ๊ถŒํ•œ์ด ๋ช‡๊ฐœ ๋˜์–ด์žˆ๋Š”๊ฐ€? ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ถŒํ•œ์„ ๋ฆฌํ„ดํ•œ๋‹ค. 
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		
		Collection<SimpleGrantedAuthority> collectors = new ArrayList<>(); // ๋‚ด๊ฐ€ GrantedAuthority ์ƒ์†๋ฐ›๋Š” ๊ฐ์ฒด๋ฅผ new ํ•ด๋„๋œ๋‹ค.
		collectors.add(new SimpleGrantedAuthority("ROLE_"+role));
		// "ROLE_"+role ๋กœ ํ•ด์•ผ์ง€ ์Šคํ”„๋ง์ด ์ธ์‹ํ•œ๋‹ค. ๊ทœ์น™! 
		return collectors;
	}

	
	// ๊ณ„์ •์ด ๋งŒ๋ฃŒ๋˜์—ˆ๋Š”๊ฐ€๋ฅผ ์ฒดํฌํ•˜์—ฌ ๋ฆฌํ„ดํ•œ๋‹ค(true:๋งŒ๋ฃŒ์•ˆ๋จ)
	// ์ข€ ๋” ๊นŠ๊ฒŒ ๋“ค์–ด๊ฐ€๋ฉด ๋งˆ์ง€๋ง‰ ์ ‘์†์‹œ๊ฐ„๊ณผ ํ˜„์žฌ ์„ธ์…˜์„ ๋น„๊ตํ•˜๋Š” ๋“ฑ์œผ๋กœ ํ™œ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค. 
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	// ๊ณ„์ •์ด ์ž ๊ฒจ์žˆ๋Š”์ง€ ์ฒดํฌํ•˜์—ฌ ๋ฆฌํ„ดํ•œ๋‹ค(true:์ž ๊ธฐ์ง€ ์•Š์Œ)
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	// ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งŒ๋ฃŒ๋˜์—ˆ๋Š”์ง€ ์ฒดํฌํ•˜์—ฌ ๋ฆฌํ„ดํ•œ๋‹ค.(true:๋งŒ๋ฃŒ์•ˆ๋จ)
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	// ํ•ด๋‹น๊ณ„์ •์ด ํ™œ์„ฑํ™” ๋˜์–ด์žˆ๋Š”์ง€ ์ฒดํฌํ•˜์—ฌ ๋ฆฌํ„ดํ•œ๋‹ค(true:ํ™œ์„ฑํ™”)
	@Override
	public boolean isEnabled() {
		return true;
	}
}

 

 

 

username, password์˜ getter, setter์ด ๋งŒ๋“ค์–ด์ ธ์žˆ๊ธฐ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ ์•ˆํ•ด๋„๋œ๋‹ค.

hasRole์ด ๋ชจ์ด๋ฉด getAuthorities๋กœ ํ˜ธ์ถœ ํ•ด์•ผํ•œ๋‹ค.

 

 

์ด ๋ชจ๋“ ๊ฒƒ์„ ํ•˜๋ฉด ์„ธ์…˜์— ์Šคํ”„๋ง์‹œํ๋ฆฌํ‹ฐ๋ฅผ ๋„ฃ์–ด๋†“๋Š”๋‹ค.์Šคํ”„๋ง์‹œํ๋ฆฌํ‹ฐ ์•ˆ์—๋Š” ์–ด์„ ํ‹ฐ๊ฐ€ ์žˆ๋‹ค.

 

 

 

 

4. ์•„์ด๋””์™€ ํŒจ์Šค์›Œ๋“œ ์ €์žฅ ์‹œ ํŒจ์Šค์›Œ๋“œ hash๋กœ ์•”ํ˜ธํ™”ํ•˜๊ธฐ

 

-securityConfig ์ˆ˜์ •

์š”์ฆ˜์€ SHA256๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์Šคํ”„๋ง์€ BCrypt ์•”ํ˜ธํ™” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋ณตํ˜ธํ™”๊ฐ€ ์•ˆ๋จ. ์ฆ‰ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์žŠ์–ด๋ฒ„๋ฆฌ๋ฉด ๋„ˆ๋„๋ชจ๋ฅด๊ณ  ๋‚˜๋„๋ชจ๋ฅด๊ณ  ๋ชจ๋‘๊ฐ€ ๋ชจ๋ฆ„.

	@Bean
	public BCryptPasswordEncoder Encoded() {
		return new BCryptPasswordEncoder();
	}

 

๋นˆ์„ ๋ถ™์—ฌ์•ผ ๋ฉ”๋ชจ๋ฆฌ์— ๋œฌ๋‹ค.

 

-UserService.java

package com.cos.blog.service;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cos.blog.model.ReturnCode;
import com.cos.blog.model.user.User;
import com.cos.blog.model.user.dto.ReqJoinDto;
import com.cos.blog.model.user.dto.ReqLoginDto;
import com.cos.blog.repository.UserRepository;

@Service
public class UserService {

	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private HttpSession session;
	
	@Autowired
	private BCryptPasswordEncoder passwordEncoder;
	
	// result = 0 ๋น„์ •์ƒ, 1 ์ •์ƒ, -1 DB ์˜ค๋ฅ˜, -2 ์•„์ด๋”” ์ค‘๋ณต
	@Transactional
	public int ํšŒ์›๊ฐ€์ž…(ReqJoinDto dto) {
		try {
			int result = userRepository.findByUsername(dto.getUsername());
			
			if(result == 1) {
				return ReturnCode.์•„์ด๋””์ค‘๋ณต;
			}else {
				//ํŒจ์Šค์›Œ๋“œ ์•”ํ˜ธํ™”ํ•˜๊ธฐ 
				String encodePassword = passwordEncoder.encode(dto.getPassword());
				dto.setPassword(encodePassword);
				return userRepository.save(dto);
			}
			
		} catch (Exception e) {
			throw new RuntimeException();
		}
	}
	
	public User ๋กœ๊ทธ์ธ(ReqLoginDto dto) {
		return userRepository.findByUsernameAndPassword(dto);
	}
	
	public int ์ˆ˜์ •์™„๋ฃŒ(int id, String password, String profile) {
		
		int result = userRepository.update(id, password, profile);
		
		if(result == 1) { // ์ˆ˜์ • ์„ฑ๊ณต
			User user = userRepository.findById(id);
			session.setAttribute("principal", user);
			
			return 1;
		}else { // ์ˆ˜์ • ์‹คํŒจ
			return -1;
		}
	}
}

 

 

- SecurityConfig

๋กœ๊ทธ์ธํ• ๋•Œ์—๋„ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ๊ฒŒ

	@Autowired
	protected UserDetailsService userDetailsService;

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

 

 

- usercontroller ์‚ญ์ œ

	@PostMapping("/user/login")
	public ResponseEntity<?> login(
			@Valid @RequestBody ReqLoginDto dto, 
			BindingResult bindingResult
			) {
		
		// request ๊ฒ€์ฆ = AOP๋กœ ์ฒ˜๋ฆฌํ•  ์˜ˆ์ •
		
		// ์„œ๋น„์Šค ํ˜ธ์ถœ
		User principal = userService.๋กœ๊ทธ์ธ(dto);

		if(principal != null) {
			session.setAttribute("principal", principal);
			return new ResponseEntity<RespCM>(new RespCM(200, "ok"), HttpStatus.OK);
		}else {
			return new ResponseEntity<RespCM>(new RespCM(400, "fail"), HttpStatus.BAD_REQUEST);
		}
		
	}

 

 

 

 

 

๊ธฐ์กด์˜ ์—์ด์ž‘์Šค๋กœ ์š”์ฒญํ•˜๊ณ  ๋ฐ›์•—๋˜ ๊ฒƒ์„ / ๋กœ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ง€์„  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ jsonํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ํ•ด์•ผํ•œ๋‹ค. ๋งคํผ๊ฐ€ ๋“ค๊ณ ์žˆ๋Š” ์˜ค๋ธŒ์ ํŠธ ๋ณ€ํ™˜ํ•˜๋Š”๊ฒƒ์„ ์‚ฌ์šฉ

 

 

- SecurityConfig.java ์ˆ˜์ •

package com.cos.blog.config;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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.method.configuration.EnableGlobalMethodSecurity;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import com.cos.blog.model.RespCM;
import com.fasterxml.jackson.databind.ObjectMapper;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // ์ง„์ž…๋˜๊ธฐ ์ง์ „์— ๋ฉ”๋ชจ๋ฆฌ์— ๋„์šธ ๊ฒƒ ์ด๋‹ค.
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Bean
	public BCryptPasswordEncoder encoded() {
		return new BCryptPasswordEncoder();
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception { //๋ชจ๋“  ์š”์ฒญ์„ ๋ฐ›๋Š”๋‹ค. 
		http.csrf().disable();
		
		http.authorizeRequests()
			.antMatchers("/user/profile/**","/post/write/**","/post/update/**","/post/delete/**","/post/detail/**").authenticated()
			.antMatchers("/amdin/**").access("hasRole('ROLE_ADMIN')or hasRole('ROLE_MANAGER')")//๊ถŒํ•œ ์„ค์ •,USER.java์—์„œ๋„ ์„ค์ •ํ•ด์ฃผ๊ณ  access๋งŒ ํ•ด์ค€๋‹ค.
			.anyRequest().permitAll()
		.and() //์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ํผ ๋กœ๊ทธ์ธ์ด ์•„๋‹ˆ๋‹ค. ์›น์—์„œ๋Š” ํผ ๋กœ๊ทธ์ธ๋ฐฉ์‹์„ ๋งŽ์ด ์“ด๋‹ค.
			.formLogin()
			.loginPage("/user/login") // ๊ทธ๋ƒฅ ์ฃผ์†Œ๋กœ ๊ฐ€๊ณ ์‹ถ์œผ๋ฉด defaultSuccessUrl()๋กœ ๊ฐ€๋ฉด ๋˜๊ณ , ๊ทธ ์ „์— ๋ฌด์–ธ๊ฐˆ ์ˆ˜ํ–‰ํ•˜๊ณ ์‹ถ์œผ๋ฉดsuccessHandler์„ ์‚ฌ์šฉํ•˜์—ฌ new ํ• ์ˆ˜ ์žˆ๋‹ค.
			.loginProcessingUrl("/user/loginProc") // POST๋งŒ ๋‚š์•„ ์ฑ”
			.failureHandler(new AuthenticationFailureHandler() {
				
				@Override
				public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
						AuthenticationException exception) throws IOException, ServletException {
					System.out.println("์‹คํŒจ~~~~~~~~~~");
					System.out.println(exception.getMessage());
					System.out.println(exception.getLocalizedMessage());
					System.out.println(exception.toString());
					
				}
			})
			.successHandler(new AuthenticationSuccessHandler() {

				@Override
				public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
						Authentication authentication) throws IOException, ServletException {
				PrintWriter out= response.getWriter();	
				ObjectMapper mapper = new ObjectMapper();
				String jsonString = mapper.writeValueAsString(new RespCM(200,"ok"));
				System.out.println(jsonString);
				out.print(jsonString);
				out.flush();
					
				
				
				}
			});
			//.defaultSuccessUrl("/");// successHamdler์‚ฌ์šฉ ๊ฐ€๋Šฅ , ํŽ˜์ด์ง€๋ฅผ ๋ฆฌํ„ด ํ•ด์ค€๋‹ค.
	}
	
	@Autowired
	protected UserDetailsService userDetailsService;
	
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(encoded());
	}
}

 

 

-login.jsp

๋กœ๊ทธ์ธ ํผ๋„ ํผ์„ ์ „์†กํ• ์ˆ˜์žˆ๊ฒŒ ์ˆ˜์ •!

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@include file="../include/nav.jsp"%>

<div class="container">

	<form>
		<div class="form-group">
			<label for="username">์œ ์ €๋„ค์ž„</label> 
			<input type="text" class="form-control" placeholder="Enter Username" id="username">
		</div>
		<div class="form-group">
			<label for="password">ํŒจ์Šค์›Œ๋“œ</label> 
			<input type="password" class="form-control" placeholder="Enter password" id="password">
		</div>
		
	</form>
	<button id="login--submit" class="btn btn-primary">๋กœ๊ทธ์ธ</button>


</div>

<script>
	$('#login--submit').on('click', function(e){
		// e.preventDefault();
		var data = {
			username: $('#username').val(),
			password: $('#password').val()
		};

		alert(data.username);
		alert(data.password);
		$.ajax({
			type: 'POST',
			url: '/user/loginProc',
			data: data,
			contentType : 'application/x-www-form-urlencoded',
			dataType : 'json'
		}).done(function(r){
			console.log(r);
			alert("๋กœ๊ทธ์ธ ์„ฑ๊ณต");
			location.href = '/';
		}).fail(function(r){
			console.log(r);
			alert("๋กœ๊ทธ์ธ ์‹คํŒจ");
		});
	});


</script>

<%@include file="../include/footer.jsp"%>



 

 

 

 

 

5. ๊ธฐ์กด์˜ ์„ธ์…˜ ์ฝ”๋“œ ์ˆ˜์ •

 

pom.xml์— ์ถ”๊ฐ€

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

์•„๋ž˜์˜ ์‹œํ๋ฆฌํ‹ฐ ํƒœ๊ทธ๋ฅผ ์œ„์— ๋ถ™์ด๋ฉด ์‹œํ๋ฆฌํ‹ฐ ์ „์šฉ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

 

<sec:authorize access="isAuthenticated()">
    <sec:authentication property="principal" var="principal" />
</sec:authorize>

 

์Šคํ”„๋ง์‹œํ๋ฆฌํ‹ฐ์— ์žˆ๋Š” ์ •๋ณด๊ฐ€ ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•ด์คŒ true๊ฐ€ ๋–จ์–ด์ง€๋ฉด ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ ์„ธ์…˜ ๊ฐ’์„ principal์— ๋„ฃ๋Š”๋‹ค๋Š” ๋œป

์›๋ž˜๋Š” principal์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ฃผ์—ˆ์ง€๋งŒ ์ด ํƒœ๊ทธ๋ฅผ ์“ฐ๋ฉด ์ž๋™์œผ๋กœ principal์ด๋ผ๊ณ  ์ง€์ •์ด ๋œ๋‹ค.

 

 

 

- nav.jsp ์ˆ˜์ •

sessionScope.principal์„ ์ „๋ถ€ ๋ณ€๊ฒฝํ•ด ์ค€๋‹ค.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<sec:authorize access="isAuthenticated()">
    <sec:authentication property="principal" var="principal" />
</sec:authorize>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>๋ธ”๋กœ๊ทธ</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>

	<nav class="navbar navbar-expand-md bg-info navbar-dark">
		<!-- Brand -->
		<a class="navbar-brand" href="/">Cos</a>

		<!-- Toggler/collapsibe Button -->
		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
			<span class="navbar-toggler-icon"></span>
		</button>

		<!-- Navbar links -->
		<div class="collapse navbar-collapse" id="collapsibleNavbar">
			<ul class="navbar-nav">

				<c:choose>
					<c:when test="${not empty principal}">
						<li class="nav-item">
						<a class="nav-link" href="/post/write">๊ธ€์“ฐ๊ธฐ</a></li>

						<li class="nav-item">
						<a class="nav-link" href="/user/profile/${principal.id}">ํšŒ์›์ •๋ณด์ˆ˜์ •</a></li>
						
						<li class="nav-item">
						<a class="nav-link" href="/user/logout">๋กœ๊ทธ์•„์›ƒ</a></li>
					</c:when>
					<c:otherwise>
						<li class="nav-item">
						<a class="nav-link" href="/user/join">ํšŒ์›๊ฐ€์ž…</a></li>

						<li class="nav-item">
						<a class="nav-link" href="/user/login">๋กœ๊ทธ์ธ</a></li>
					</c:otherwise>
				</c:choose>

			</ul>
			<img src="/media/${principal.profile}"  class="rounded-circle my__img ml-auto" 
			     width="30px" height="30px" onerror="javascript:this.src = '/images/unknown.jpg' " />
		</div>
	</nav>
	<br />

 

- postController.java ์ˆ˜์ •

์„ธ์…˜์„ ์ง€์šฐ๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์–ด๋…ธํ…Œ์ด์…˜์„ ๊ฑธ์–ด ์‚ฌ์šฉํ•˜์—ฌ๋„๋œ๋‹ค.

// ์ธ์ฆ ์ฒดํฌ
	@PostMapping("/post/write")
	public ResponseEntity<?> write(@RequestBody ReqWriteDto dto,@AuthenticationPrincipal User principal) {
		
	
		dto.setUserId(principal.getId());
		
		int result = postService.๊ธ€์“ฐ๊ธฐ(dto);
		
		if(result == 1) {
			return new ResponseEntity<RespCM>(new RespCM(200, "ok"), HttpStatus.OK);	
		}else {
			return new ResponseEntity<RespCM>(new RespCM(400, "fail"), HttpStatus.BAD_REQUEST);
		}
		
		
	}

 

 

 

- userController์ˆ˜์ •

package com.cos.blog.controller;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.cos.blog.model.RespCM;
import com.cos.blog.model.ReturnCode;
import com.cos.blog.model.user.User;
import com.cos.blog.model.user.dto.ReqJoinDto;
import com.cos.blog.service.UserService;
import com.cos.blog.util.Script;

@Controller
public class UserController {
	
	@Value("${file.path}")
	private String fileRealPath;  // ์„œ๋ฒ„์— ๋ฐฐํฌํ•˜๋ฉด ๊ฒฝ๋กœ ๋ณ€๊ฒฝํ•ด์•ผํ•จ.
	
	@Autowired
	private UserService userService;
	
	@GetMapping("/user/join")
	public String join() {
		return "/user/join";
	}
	
	@GetMapping("/user/login")
	public String login() {
		return "/user/login";
	}

	
	// ์ธ์ฆ, ๋™์ผ์ธ ์ฒดํฌ
	@GetMapping("/user/profile/{id}")
	public  String profile(@PathVariable int id,@AuthenticationPrincipal User principal) {
		
		System.out.println("UserController : profile :  "+principal.getProfile());
		if(principal.getId() == id) {
			return "/user/profile";
		}else {
			// ์ž˜๋ชป๋œ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค. ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.
			return "/user/login";
		}
	
	}
	
	// form:form ์‚ฌ์šฉํ•จ!!
	@PutMapping("/user/profile")
	public @ResponseBody String profile(
			@RequestParam int id, 
			@RequestParam String password,
			@RequestParam MultipartFile profile){
		
		UUID uuid = UUID.randomUUID();
		String uuidFilename = uuid+"_"+profile.getOriginalFilename();
		
		// nio ๊ฐ์ฒด!!
		Path filePath = Paths.get(fileRealPath+uuidFilename);
		try {
			Files.write(filePath, profile.getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		int result = userService.์ˆ˜์ •์™„๋ฃŒ(id, password, uuidFilename);
		
		if(result == 1) {
			return Script.href("์ˆ˜์ •์™„๋ฃŒ", "/");
		}else {
			return Script.back("์ˆ˜์ •์‹คํŒจ");
		}	

	}
	
	// ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ(Jackson Mapper)๋Š” request๋ฐ›์„ ๋•Œ setter๋กœ ํ˜ธ์ถœํ•œ๋‹ค.
	@PostMapping("/user/join")
	public ResponseEntity<?> join(@Valid @RequestBody ReqJoinDto dto, BindingResult bindingResult) {
		
		int result = userService.ํšŒ์›๊ฐ€์ž…(dto);
		
		if(result == ReturnCode.์•„์ด๋””์ค‘๋ณต) {
			return new ResponseEntity<RespCM>(new RespCM(ReturnCode.์•„์ด๋””์ค‘๋ณต, "์•„์ด๋””์ค‘๋ณต"), HttpStatus.OK);
		}else if(result == ReturnCode.์„ฑ๊ณต) {
			return new ResponseEntity<RespCM>(new RespCM(200, "ok"), HttpStatus.OK);
		}else {
			return new ResponseEntity<RespCM>(new RespCM(500, "fail"), HttpStatus.INTERNAL_SERVER_ERROR);
		}	
	}
	
}



 

๋“ฑ session์„ ์“ฐ๋Š” ๋ชจ๋“  ๊ณณ์— ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

 

๋งˆ์ง€๋ง‰ ์ˆ˜์—… :-)

์ˆ˜๊ณ ํ•˜์…ง์Šต๋‹ˆ๋‹น ํ—ฟ