feat(user-service): Spring Security 및 JWT 로그인 인증, 인가 구현
- Spring Security 구현 - 로그인 인증 구현 - 인증 성공 시 JWT 발급 구현
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package com.justpickup.userservice.global.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.justpickup.userservice.global.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LoginRequest {
|
||||
private String name;
|
||||
private String email;
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.justpickup.userservice.global.security;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
public class HeaderAuthorizationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
if (request.getServletPath().equals("/login")) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
String email = request.getHeader("jwt-sub");
|
||||
log.info("email jwt-sub = {}", email);
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.justpickup.userservice.global.security;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.justpickup.userservice.global.dto.LoginRequest;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
// login 리퀘스트 패스로 오는 요청을 판단
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
Authentication authentication;
|
||||
|
||||
try {
|
||||
LoginRequest credential = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class);
|
||||
|
||||
authentication = authenticationManager.authenticate(
|
||||
new UsernamePasswordAuthenticationToken(credential.getEmail(), credential.getPassword())
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
// 로그인 성공 이후 토큰 생성
|
||||
@Override
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException {
|
||||
org.springframework.security.core.userdetails.User user = (User) authResult.getPrincipal();
|
||||
|
||||
String accessToken = Jwts.builder()
|
||||
.setSubject(user.getUsername())
|
||||
.setExpiration(
|
||||
new Date(System.currentTimeMillis() + 10 * 60 * 1000)
|
||||
)
|
||||
.signWith(SignatureAlgorithm.HS512, "your-256-bit-secret")
|
||||
.setIssuer(request.getRequestURI())
|
||||
.addClaims(Map.of("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())))
|
||||
.compact();
|
||||
|
||||
String refreshToken = Jwts.builder()
|
||||
.setSubject(user.getUsername())
|
||||
.setExpiration(
|
||||
new Date(System.currentTimeMillis() + 30 * 60 * 1000)
|
||||
)
|
||||
.signWith(SignatureAlgorithm.HS512, "your-256-bit-secret")
|
||||
.setIssuer(request.getRequestURI())
|
||||
.compact();
|
||||
|
||||
Map<String, String> tokens = Map.of(
|
||||
"access_token", accessToken,
|
||||
"refresh_token", refreshToken
|
||||
);
|
||||
response.setContentType(APPLICATION_JSON_VALUE);
|
||||
new ObjectMapper().writeValue(response.getOutputStream(), tokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unsuccessfulAuthentication
|
||||
(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
|
||||
throws IOException, ServletException {
|
||||
log.warn("로그인 실패!!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.justpickup.userservice.global.security;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.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.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
LoginAuthenticationFilter loginAuthenticationFilter = new LoginAuthenticationFilter(authenticationManagerBean());
|
||||
loginAuthenticationFilter.setFilterProcessesUrl("/login");
|
||||
|
||||
http.csrf().disable();
|
||||
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
http.authorizeRequests().antMatchers("/login").permitAll();
|
||||
http.addFilter(loginAuthenticationFilter);
|
||||
http.addFilterBefore(new HeaderAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user