본문 바로가기
목차
Spring/Spring boot

스프링부트 강좌 61강(블로그 프로젝트) - 회원수정 2

by 지각생 2022. 1. 25.
728x90

출처:

https://www.youtube.com/watch?v=VESYOJWD5d8&list=PL93mKxaRDidECgjOBjPgI3Dyo8ka6Ilqm&index=63 


이번시간은 session값을 변경하려함

이건 시큐리티 때문에 좀 까다롭다.

이렇게 써주면 저 Atuthentication객체를 가져오는 것.

session에 강제 접근시도했으나 실패했음.

 

정상적인 흐름 그대로 실행하는 방법으로 다시 시도

(강의중 자바스크립트에서 username을 전송하는 구문이 빠져서 실행이 잘 안됐었음)

 

ctrl+shift+s

단축키

 

이거 하는 과정 줄인 단축키이다.

 

bean 생성

 

bean 등록

 

package com.cosblog.controller.api;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
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.RestController;

import com.cosblog.config.auth.PrincipalDetail;
import com.cosblog.dto.ResponseDto;
import com.cosblog.model.User;
import com.cosblog.service.UserService;

@RestController
public class UserApiController {
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private AuthenticationManager authenticationManager;
	//@Autowired //메서드 파라메터 대신 이렇게 넣어줘도 가능하다.
	//private HttpSession session;
	
	@PostMapping("/auth/joinProc")
	public ResponseDto<Integer> save(@RequestBody User user) {

		userService.회원가입(user);
		return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);//자바오브젝트를 JSON으로 변환해서 리턴
	}
	
	@PutMapping("/user")
	public ResponseDto<Integer> update(@RequestBody User user
			//,@AuthenticationPrincipal PrincipalDetail principal
			//,HttpSession session
			) {
		
		userService.회원수정(user);
		//여기서는 트랜잭션이 종료되기 때문에 DB에 값은 변경이 됐음.
		// 하지만 세션값은 변경되지 않은 상태이기 때문에 우리가 직접 세션값을 변경해줄 것임.
		
		//세션등록
		Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
		SecurityContextHolder.getContext().setAuthentication(authentication);
		
		
		//강제로 session에 값 저장하려 했으나 안됐음
		/*
		 * Authentication authentication= new
		 * UsernamePasswordAuthenticationToken(principal,
		 * null,principal.getAuthorities()); SecurityContext securityContext =
		 * SecurityContextHolder.getContext();
		 * securityContext.setAuthentication(authentication);
		 * session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
		 */		 		
		return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);//자바오브젝트를 JSON으로 변환해서 리턴
	}
	
	//전통적인 로그인 방식, 스프링 시큐리티 이용해서 로그인하면 이 방식 사용하지 않는다.
	/*
	 * @PostMapping("/api/user/login") public ResponseDto<Integer>
	 * login(@RequestBody User user, HttpSession session){
	 * System.out.println("UserApiController:login호출됨"); User principal =
	 * userService.로그인(user); //접근주체
	 * 
	 * if(principal != null) { session.setAttribute("principal", principal); }
	 * 
	 * return new ResponseDto<Integer>(HttpStatus.OK.value(),1);
	 * 
	 * }
	 */
}
package com.cosblog.controller;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import com.cosblog.config.auth.PrincipalDetail;


//인증이 안된 사용자들이 출입할 수 있는 경로를 /auth만 허용할 것임
//그냥 주소가 /이면 index.jsp 허용
//static이하에 있는 /js/**, /css/**, /image/**

@Controller
public class UserController {

	@GetMapping("/auth/joinForm")
	public String joinForm() {
		return "user/joinForm";
	}
	
	@GetMapping("/auth/loginForm")
	public String loginForm() {
		return "user/loginForm";
	}
	
	@GetMapping("/user/updateForm")
	public String updateForm(@AuthenticationPrincipal PrincipalDetail principal) {
		return "user/updateForm";
	}
}
package com.cosblog.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.crypto.bcrypt.BCryptPasswordEncoder;

import com.cosblog.config.auth.PrincipalDetailService;

//빈 등록 : 스프링 컨테이너에서 객체를 관리할 수 있게 하는 것

//아래 3개는 세트라고 생각해라
@Configuration //빈등록 IOC관리
@EnableWebSecurity //시큐리티 필터가 등록이 된다.
@EnableGlobalMethodSecurity(prePostEnabled = true)//특정 주소로 접근을 하면 권한 및 인증을 미리 체크하겠다는 뜻.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private PrincipalDetailService principalDetailService;
	

	
	@Bean
	public AuthenticationManager authenticationManagerBean() throws Exception {
		// TODO Auto-generated method stub
		return super.authenticationManagerBean();
	}

	@Bean //IOC가 됨
	public BCryptPasswordEncoder encodePWD() {
		return new BCryptPasswordEncoder();
	}
	
	//시큐리티가 대신 로그인해주는데 password를 가로채기를 하는데
	//해당 password가 뭘로 해쉬가 되어 회원가입이 되었는지 알아야
	//같은 해쉬로 암호화해서 DB에 있는 해쉬랑 비교할 수 있음.
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(principalDetailService).passwordEncoder(encodePWD());
	}
	
	
	@Override
	protected void configure(HttpSecurity http)throws Exception{
		http
		.csrf().disable() //csrf 토큰 비활성화 (테스트시 걸어두는 게 좋음)
			.authorizeRequests()
			.antMatchers("/", "/auth/**", "/js/**", "/css/**", "/image/**","/dummy/**")
			.permitAll()
			.anyRequest()
			.authenticated()
		.and()
			.formLogin()
			.loginPage("/auth/loginForm")
			.loginProcessingUrl("/auth/loginProc")//스프링 시큐리티가 해당 주소로 요청오는 로그인을 가로채서 대신 로그인 해준다.
			.defaultSuccessUrl("/");
			//.failureUrl("/fail");//실패시 보낼 Url위치 적는 방법
	}
}
package com.cosblog.service;



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.cosblog.model.RoleType;
import com.cosblog.model.User;
import com.cosblog.repository.UserRepository;

//스프링이 컴포넌트 스캔을 통해서 bean에 등록을 해줌
@Service
public class UserService {

	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private BCryptPasswordEncoder encoder;
	

	
	@Transactional
	public void 회원가입(User user) {
		
		String rawPassword = user.getPassword(); //1234원문
		String encPassword = encoder.encode(rawPassword); //해쉬
		user.setPassword(encPassword);
		user.setRole(RoleType.USER);
		userRepository.save(user);
	}

	@Transactional
	public void 회원수정(User user) {
		//수정시에는 영속성 컨텍스트 User 오브젝트를 영속화시키고, 영속화된 User 오브젝트를 수정
		//select를 해서 User오브젝트를 DB로부터 가져오는 이유는 영속화를 하기 위해서!
		//영속화된 오브젝트를 변경하면 자동으로 DB에 update문을 날려주거든요.
		User persistance = userRepository.findById(user.getId()).orElseThrow(()->{
			return new IllegalArgumentException("회원 찾기 실패");
		});
		String rawPassword = user.getPassword();
		String encPassword = encoder.encode(rawPassword);
		persistance.setPassword(encPassword);
		persistance.setEmail(user.getEmail());
		
		//회원수정 함수 종료시 = 서비스 종료 = 트랜잭션 종료 = commit이 자동으로 됩니다.
		//영속화된 persistance 객체의 변화가 감지되면 더티체킹이 되어 update문을 날려줌.
	}
	
	
	/* 이 로그인도 사용 안 할거라 삭제
	 * @Transactional(readOnly = true)//Select할 때 트랜잭션 시작, 서비스 종료시에 트랜잭션 종료(정합성)
	 * public User 로그인(User user) { return
	 * userRepository.findByUsernameAndPassword(user.getUsername(),
	 * user.getPassword()); }
	 */
}
let index = {
  init: function () {
    $("#btn-save").on("click", () => {
      //()=>{} this를 바인딩하기 위해서!
      this.save();
    });
    $("#btn-update").on("click", () => {
      //()=>{} this를 바인딩하기 위해서!
      this.update();
    });
    // $("#btn-login").on("click", () => {
    //   //()=>{} this를 바인딩하기 위해서!
    //   this.login();
    // });
  },

  save: function () {
    //alert("user의 save함수 호출됨");
    let data = {
      //id값으로 찾아서 값 가져옴
      username: $("#username").val(),
      password: $("#password").val(),
      email: $("#email").val(),
    };

    //console.log(data);

    // ajax호출시 default가 비동기 호출
    // ajax 통신을 이용해서 3개의 데이터를 json으로 변경하여 insert요청!
    // ajax가 통신을 성공하고 서버가 json을 리턴해주면 자동으로 자바 오브젝트로 변환해주네요.
    $.ajax({
      //회원가입 수행 요청
      type: "POST",
      url: "/auth/joinProc",
      data: JSON.stringify(data), //http body 데이터
      contentType: "application/json; charset=utf-8", //body데이터가 어떤 타입인지(MIME)
      dataType: "json", // 요청을 서버로 해서 응답이 왔을 때 기본적으로 모든 것이 문자열(생긴게 json이라면)=> javascript 오브젝트로 변경
    })
      .done(function (resp) {
        alert("회원가입이 완료되었습니다.");
        //console.log(resp);
        location.href = "/";
      })
      .fail(function (error) {
        alert(JSON.stringify(error));
      }); //ajax 통신을 이용해서 3개의 데이터를 json으로 변경히여 insert 요청!!
  },

  update: function () {
    let data = {
      id: $("#id").val(),
      username: $("#password").val(),
      password: $("#password").val(),
      email: $("#email").val(),
    };
    $.ajax({
      type: "PUT",
      url: "/user",
      data: JSON.stringify(data),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
    })
      .done(function (resp) {
        alert("회원수정이 완료되었습니다.");
        location.href = "/";
      })
      .fail(function (error) {
        alert(JSON.stringify(error));
      });
  },

  // login: function () {
  //   //alert("user의 save함수 호출됨");
  //   let data = {
  //     //id값으로 찾아서 값 가져옴
  //     username: $("#username").val(),
  //     password: $("#password").val(),
  //     email: $("#email").val(),
  //   };

  //   //console.log(data);

  //   // ajax호출시 default가 비동기 호출
  //   // ajax 통신을 이용해서 3개의 데이터를 json으로 변경하여 insert요청!
  //   // ajax가 통신을 성공하고 서버가 json을 리턴해주면 자동으로 자바 오브젝트로 변환해주네요.
  //   $.ajax({
  //     //회원가입 수행 요청
  //     type: "POST",
  //     url: "/api/user/login",
  //     data: JSON.stringify(data),
  //     contentType: "application/json; charset=utf-8", //body데이터가 어떤 타입인지(MIME)
  //     dataType: "json", // 요청을 서버로 해서 응답이 왔을 때 기본적으로 모든 것이 문자열(생긴게 json이라면)=> javascript 오브젝트로 변경
  //   })
  //     .done(function (resp) {
  //       alert("로그인이 완료되었습니다.");

  //       location.href = "/";
  //     })
  //     .fail(function (error) {
  //       alert(JSON.stringify(error));
  //     }); //ajax 통신을 이용해서 3개의 데이터를 json으로 변경히여 insert 요청!!
  // },
};

index.init();
728x90

댓글