jpablog : login with spring security
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package com.example.jpablog.config;
|
||||
|
||||
import com.example.jpablog.config.auth.PrincipalDetailService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
@@ -10,22 +12,36 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
@Configuration // bean 등록
|
||||
@RequiredArgsConstructor
|
||||
@EnableWebSecurity // 시큐리티 필터 등록
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true) // 특정 주소 접근시 먼저 권한 및 인증 체크
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final PrincipalDetailService principalDetailService;
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder encodePWD() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
// 시큐리티가 대신 로그인 할때 어떤 해시를 사용했는지 알아야 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/**", "/images/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and().formLogin().loginPage("/auth/loginForm");
|
||||
.csrf().disable() // csrf 토큰 비활성화
|
||||
.authorizeRequests() // 요청에 대한 인증
|
||||
.antMatchers("/", "/auth/**", "/js/**", "/css/**", "/images/**").permitAll() // 해당 주소로 들어오면 모두 허가
|
||||
.anyRequest().authenticated() // 나머지 요청은 모두 인증을 거쳐야 함
|
||||
.and()
|
||||
.formLogin().loginPage("/auth/loginForm") // 로그인 폼 지정
|
||||
.loginProcessingUrl("/auth/loginProc") // 해당 주소로 들어오는 로그인 요청을 가로채서 스프링 시큐리티가 로그인
|
||||
.defaultSuccessUrl("/"); // 정상 로그인 완료 후 이동 URL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.example.jpablog.config.auth;
|
||||
|
||||
import com.example.jpablog.model.User;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
|
||||
public class PrincipalDetail implements UserDetails {
|
||||
private final User user;
|
||||
|
||||
public PrincipalDetail(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return user.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
// 계정 만료 여부 ( false : 만료 )
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 계정이 잠금 여부 ( false : 잠김 )
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 비밀번호 만류 여부 ( false : 만료 )
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 계정 활성화 여부 ( false : 비활성화 )
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 계정의 권한 목록 리턴
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
Collection<GrantedAuthority> collections = new ArrayDeque<>();
|
||||
collections.add(() -> "ROLE_" + user.getRole());
|
||||
return collections;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.jpablog.config.auth;
|
||||
|
||||
import com.example.jpablog.model.User;
|
||||
import com.example.jpablog.repository.UserRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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
|
||||
@RequiredArgsConstructor
|
||||
public class PrincipalDetailService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
// 스프링이 로그인 요청시 username, password 변수 체크
|
||||
// password 는 스프링 시큐리티가 알아서 처리
|
||||
// username 은 DB에 있는지 체크
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
User principal = userRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("해당 사용자를 찾을 수 없습니다."));
|
||||
|
||||
return new PrincipalDetail(principal); // 시큐리티 세션에 유저 정보 저장
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.example.jpablog.controller;
|
||||
|
||||
import com.example.jpablog.config.auth.PrincipalDetail;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class BoardController {
|
||||
|
||||
// 파라미터로 시큐리티 세션 접근 : @AuthenticationPrincipal PrincipalDetail principal
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "index";
|
||||
|
||||
@@ -5,10 +5,13 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository // 생략가능
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
|
||||
// select * from user where username =?
|
||||
Optional<User> findByUsername(String username);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ spring:
|
||||
jpa:
|
||||
open-in-view: true
|
||||
hibernate:
|
||||
ddl-auto: create
|
||||
ddl-auto: update
|
||||
# naming:
|
||||
# physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
|
||||
use-new-id-generator-mappings: false
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<%@include file="../layout/header.jsp"%>
|
||||
|
||||
<div class="container">
|
||||
<form action="#" method="post">
|
||||
<form action="/auth/loginProc" method="post">
|
||||
<div class="form-group">
|
||||
<label for="username">Username:</label>
|
||||
<input name="username" type="text" class="form-control" placeholder="Enter username" id="username">
|
||||
@@ -12,11 +12,6 @@
|
||||
<label for="password">Password:</label>
|
||||
<input name="password" type="password" class="form-control" placeholder="Enter password" id="password">
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<label class="form-check-label">
|
||||
<input name="remember" class="form-check-input" type="checkbox"> Remember me
|
||||
</label>
|
||||
</div>
|
||||
<button id="btn-login" type="submit" class="btn btn-primary">로그인</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user