Notice
Recent Posts
Recent Comments
Link
Coding Note
SpringBoot) 블로그 프로젝트_8.로그인,암호화, 글등록 본문
1. 해쉬 암호화
https://bamdule.tistory.com/53
시큐리티는 비번 암호화되어있어야만 로그인이 된다!
Q1. 해쉬
- 고정 길이의 문자 값으로 변경
Q2. 해쉬 장점
- 내용 변경에 따라 해쉬값이 변경되는데 값을 비교해서 변경되었는지 확인할 수 있다.
- SecurityConfig
//빈 등록: 스프링컨테이너에서 객체를 관리할 수 있게 하는 것
//아래 3개의 어노테이션은 시큐리티 사용시 세트임
@Configuration //빈등록(IoC관리)
@EnableWebSecurity//시큐리티 필터 추가 = 스프링 시큐리티 필터가 등록 된다.
@EnableGlobalMethodSecurity(prePostEnabled = true) //특정 주소로 접근을 하면 권한 및 인증을 미리 체크하겠다는 뜻
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private PrincipalDetailService principalDetailService;
//비밀번호 해쉬 암호화
@Bean //Ioc가 됨
public BCryptPasswordEncoder encodePWD() {
return new BCryptPasswordEncoder();
}
//시큐리티가 대신 로그인해주는데 password를 가로채기를 하는데
//해당 password가 뭘로 해쉬가 되어 회원가입이 되었는지 알아야 같은 해쉬로 암호화해서 DB에 있는 해쉬랑 비교할 수 있음
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(principalDetailService).passwordEncoder(encodePWD());//pwd 비교
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() //csrf 토큰 비활성화(테스트시 걸어두는게 좋음!)
.authorizeRequests()
.antMatchers("/", "/auth/**", "/js/**", "/css/**", "/image/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/auth/loginForm")
.loginProcessingUrl("/auth/loginProc")
.defaultSuccessUrl("/");//스프링 시큐리티가 해당 주소로 요청오는 로그인을 가로채서 로그인 해준다.
}
}
- PrincipalDetail
//스프링 시큐리티가 로그인 요청을 가로챠서 로그인을 진행하고 완료가 되면 UserDetails 타입의 오브젝트를
//스프링 시큐리티의 고유한 세션 저장소에 저장을 해준다.
@Getter
public class PrincipalDetail implements UserDetails{
private User user; //콤포지션 : 객체를 품고 있는 것
public PrincipalDetail(User user) {
this.user =user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
//계정이 만료되지 않았는지 리턴함.(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;
}
//계정이 갖고있는 권한 목록을 리턴함(권한이 여러개 있을 수 있어서 루프를 돌아야 하는데 우리는 한개만 리턴)
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collectors = new ArrayList<>();
collectors.add(()-> { return "ROLE_"+user.getRole();});
return collectors;
}
}
- PrincipalDetailService
@Service //Bean 등록
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("해당 사용자를 찾을 수 없습니다. :"+username);
}) ;
return new PrincipalDetail(principal); //시큐리티 세션의 유저 정보가 저장됨.
}
}
- UserService
//스프링이 컴포넌트 스캔을 통해서 Bean에 등록 해줌. => Ioc해줌
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder encoder;
@Transactional
public void 회원가입(User user) {
String rawPassword = user.getPassword();//1234원문
String encPasswrod = encoder.encode(rawPassword);//해쉬
user.setPassword(encPasswrod);
user.setRole(RoleType.USER);
userRepository.save(user);
}
}
2. csrf/xss
XSS
- 자바스크립트 공격
Lucy XSS Filter
- XSS(Cross Site Scripting) 공격을 방어하는 Java 라이브러리
http://naver.github.io/lucy-xss-filter/kr/
CSRF(Cross Site Request Forgery)
- 사이트 간 위조 요청
CSRF(Cross Stie Request Forgery) : 사이트간 요청 위조
웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격방법을 의미한다 - 나무위키
https://sj602.github.io/2018/07/14/what-is-CSRF/
3. 로그인 구현
로그인 구현완
- loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<form action="/auth/loginProc" method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" class="form-control" placeholder="Enter username" id="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password" class="form-control" placeholder="Enter password" id="password">
</div>
<button id="btn-login" class="btn btn-primary">로그인</button>
</form>
</div>
<%@include file="../layout/footer.jsp"%>
- UserRepository
public interface UserRepository extends JpaRepository<User, Integer>{
//select * from user where username =1?;
Optional<User> findByUsername(String username);
}
- UserApiController
package com.cos.blog.controller.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.cos.blog.dto.ResponseDto;
import com.cos.blog.model.User;
import com.cos.blog.service.UserService;
@RestController
public class UserApiController {
@Autowired
private UserService userService;
@PostMapping("/auth/joinProc")
public ResponseDto<Integer> save(@RequestBody User user) { //json 형식을 받을때 @RequestBody 선언함
System.out.println("UserApiController: save 호출 완료");
userService.회원가입(user);
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1); // 200 : http 전송 성공
}
}
4. 글쓰기 구현
- 썸머 노트 사용
아래 코드 복붙!
물론 파일, 사진 업로드도 수월하게 가능!
- Board
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder//빌더 패턴
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)//auto_increment
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob//대용량 데이터 사용시
private String content;//섬머노트 라이브러리 사용 - <html>태그가 섞여서 디자인이됨
private int count;//조회수
@ManyToOne(fetch = FetchType.EAGER)//many =board, user= one 즉, 한명이 여러개의 게시물 작성 가능
@JoinColumn(name="userId")
private User user;//DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다. - ORM을 사용시 오브젝트 사용 가능
@OneToMany(mappedBy="board", fetch = FetchType.EAGER)//mappedBy 연관관계의 주인이 아니다(난 FK가 아니예요!) DB에 컬럼을 만들지 마세요!
private List<Reply> reply;
@CreationTimestamp
private Timestamp createDate;
}
- BoardRepository
public interface BoardRepository extends JpaRepository<Board, Integer>{
}
- BoardController
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
@GetMapping({"", "/"})
public String index(Model model) {
model.addAttribute("boards", boardService.글목록());
return "index"; //viewResolver 작동!
}
//USER 권한 필요
@GetMapping("/board/saveForm")
public String saveForm() {
return "board/saveForm";
}
}
- BoardService
//스프링이 컴포넌트 스캔을 통해서 Bean에 등록 해줌. => Ioc해줌
@Service
public class BoardService {
@Autowired
private BoardRepository boardRepository;
@Transactional
public void 글쓰기(Board board, User user) {//title, content
board.setCount(0);
board.setUser(user);
boardRepository.save(board);
}
public List<Board> 글목록(){
return boardRepository.findAll();
}
}
- BoardApiController
@RestController
public class BoardApiController {
@Autowired
private BoardService boardService;
@PostMapping("/api/board")
public ResponseDto<Integer> save(@RequestBody Board board, @AuthenticationPrincipal PrincipalDetail principal) {
boardService.글쓰기(board, principal.getUser());
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1); // 200 : http 전송 성공
}
}
3일 차 스터디 완
'SpringBoot > 블로그만들기PJ' 카테고리의 다른 글
SpringBoot) 블로그 프로젝트_10. 글 수정, 삭제, 회원 수정 (0) | 2022.03.19 |
---|---|
SpringBoot) 블로그 프로젝트_9. 페이징 처리, Spring Security, 글 상세보기 (0) | 2022.03.19 |
SpringBoot) 블로그 프로젝트_7.부트스트랩을 이용한 화면 구현2, 회원가입 (0) | 2022.03.18 |
SpringBoot) 블로그 프로젝트_6.부트스트랩을 이용한 화면 구현 (0) | 2022.03.17 |
SpringBoot) 블로그 프로젝트_5.JSON 통신 이론 (0) | 2022.03.17 |
Comments