Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 스프링부트 회원가입
- springboot 사이드프로젝트
- 유니티기초
- 스프링부트 update
- 스프링부트 미니프로젝트
- 괄호 회전하기 파이썬
- 프로그래머스 괄호 회전하기 python
- python 괄호 회전하기
- spring jpa 게시판
- typescript 기초문법
- 스프링게시판프로젝트
- 타입스크립트 기초문법
- 타입스크립트 기본문법
- 스프링 게시판 만들기
- 파이썬 괄호 회전하기
- springboot 게시판만들기
- 타입스크립트 기초
- 스프링부트 게시판만들기
- 파이썬 기초
- 스프링부트 블로그만들기
- springboot 게시판
- 스프링부트 블로그
- springboot 미니프로젝트
- springboot 게시판 프로젝트
- 유니티Material
- JS기초
- jpa 게시판
- 유니티
- 유니티Cube
- spring jpa 사이드프로젝트
Archives
- Today
- Total
Digking's cave
My First Blog Project (19) : 블로그 회원정보 수정 본문
728x90
@AuthenticationPrincipal PrincipalDetail principal 을 작성하면
얘는 Authentication 객체를 가져온다
AuthenticationManager 가 UsernamePasswordAuthenticationToken을 받아서 Authentication 객체를 만든다.
UsernamePasswordAuthenticationToken 을 UserDetailService한테 던지면,
UserDetailService가 User 확인하고 있으면 Authentication 만든다.
회원정보 변경 후에 세션을 강제로 만들어서 저장해서, 재로그인없이 바로 변경된 회원정보를 볼 수 있게 한다.
PrincipalDetailService.java
package com.cos.blog.config.auth;
import com.cos.blog.model.User;
import com.cos.blog.repository.UserRepository;
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;
@Service
public class PrincipalDetailService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
// 스프링이 로그인 요청을 가로챌 때, username과 password 변수 2개를 가로채는데 password는 알아서 처리함
// 우리는 username이 DB에 있는지만 확인해주면 된다.
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User principal = userRepository.findByUsername(username)
.orElseThrow(()->{
return new UsernameNotFoundException("해당 사용자를 찾을 수 없습니다.");
});
//바로 user타입의 principal을 return할 수 없고, PrincipalDetail을 새로 생성해서 return
return new PrincipalDetail(principal); // 이 때 시큐리티의 세션에 유저 정보가 저장된다
}
}
SecurityConfig.java
package com.cos.blog.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.cos.blog.config.auth.PrincipalDetailService;
// 빈 등록 : 스프링 컨테이너에서 객체를 관리할 수 있게 하는 것
@Configuration // 빈등록 (IoC관리)
@EnableWebSecurity // 시큐리티 필터가 등록이 된다.
//Controller에서 특정 권한이 있는 유저만 접근을 허용하려면 @PreAuthorize 어노테이션을 사용하는데, 해당 어노테이션을 활성화 시키는 어노테이션이다.
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private PrincipalDetailService principalDetailService;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
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("/"); // 스프링 시큐리티가 해당 주소로 요청오는 로그인을 가로채서 대신 로그인 해준다.
}
}
UserApiController.java
package com.cos.blog.controller.api;
import com.cos.blog.config.auth.PrincipalDetail;
import com.cos.blog.config.auth.PrincipalDetailService;
import com.cos.blog.dto.ResponseDto;
import com.cos.blog.model.RoleType;
import com.cos.blog.model.User;
import com.cos.blog.service.UserService;
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.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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 javax.servlet.http.HttpSession;
@RestController
public class UserApiController {
@Autowired
private UserService userService;
@Autowired
private AuthenticationManager authenticationManager;
@PostMapping("/auth/joinProc")
public ResponseDto<Integer> save(@RequestBody User user) { // username, password, email
userService.회원가입(user);
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);
}
@PutMapping("/user")
public ResponseDto<Integer> update(@RequestBody User user) { // key=value, x-www-form-urlencoded
userService.회원수정(user);
// 여기서는 트랜잭션이 종료되기 때문에 DB에 값은 변경이 됐음.
// 하지만 세션값은 변경되지 않은 상태이기 때문에 우리가 직접 세션값을 변경해줄 것임.
// 세션 등록
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);
}
}
UserService.java
package com.cos.blog.service;
import com.cos.blog.model.RoleType;
import com.cos.blog.model.User;
import com.cos.blog.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@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.setRoles(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문을 자동으로 날려준다.
}
}
updateForm.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ include file="../layout/header.jsp" %>
<div class="container">
<form>
<input type="hidden" id="id" value="${principal.user.id}" />
<div class="form-group">
<label for="username">Username:</label>
<input type="text" value="${principal.user.username}" class="form-control" placeholder="Enter Username" id="username" readonly>
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input type="password" class="form-control" placeholder="Enter password" id="pwd">
</div>
<div class="form-group">
<label for="email">Email address:</label>
<input type="email" value="${principal.user.email}" class="form-control" placeholder="Enter email" id="email">
</div>
</form>
<button id="btn-update" class="btn btn-primary">회원수정 완료</button>
</div>
<script src="/js/user.js"></script>
<%@ include file="../layout/footer.jsp" %>
user.js
let index = {
init: function(){
$("#btn-save").on("click",()=>{ // 화살표함수 쓰는 이유는 this를 바인딩하기 위해서
this.save();
});
$("#btn-update").on("click",()=>{ // 화살표함수 쓰는 이유는 this를 바인딩하기 위해서
this.update();
});
},
save:function(){
let data = {
username: $("#username").val(),
password: $("#pwd").val(),
email: $("#email").val()
};
// 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 object로 변경해줌
}).done(function(resp){
alert("회원가입 완료되었습니다.");
location.href = "/";
}).fail(function(error){
alert(JSON.stringify(error));
});
},
update:function(){
let data = {
id:$("#id").val(),
username:$("#username").val(),
password: $("#pwd").val(),
email: $("#email").val()
};
$.ajax({
type:"PUT",
url:"/user",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
}).done(function(resp){
alert("회원정보 수정이 완료되었습니다.");
location.href = "/";
}).fail(function(error){
alert(JSON.stringify(error));
});
}
}
index.init();
반응형
'Spring > My First Blog Project' 카테고리의 다른 글
My First Blog Project (18) : 게시판 글 상세보기 / 삭제하기 / 수정하기 (0) | 2022.12.26 |
---|---|
My First Blog Project (17) : 게시판 글 목록 페이징처리 (0) | 2022.12.26 |
My First Blog Project (16) : 게시판 글 목록 보기 (0) | 2022.12.26 |
My First Blog Project (15) : 게시판 글쓰기 (0) | 2022.12.21 |
My First Blog Project (14) : SpringSecurity 로그인 구현 (0) | 2022.12.21 |