Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.synapse.account_service.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

@Configuration
public class ObjectMapperConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,50 @@

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.synapse.account_service.convert.authority.CustomAuthorityMapper;
import com.synapse.account_service.filter.JwtAuthenticationFilter;
import com.synapse.account_service.service.CustomUserDetailsService;
import com.synapse.account_service.service.handler.LoginFailureHandler;
import com.synapse.account_service.service.handler.LoginSuccessHandler;

import lombok.RequiredArgsConstructor;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final CustomUserDetailsService customUserDetailsService;
private final LoginSuccessHandler loginSuccessHandler;
private final LoginFailureHandler loginFailureHandler;
private final ObjectMapper objectMapper;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
http.csrf(csrf -> csrf.disable())
.formLogin(form -> form.disable())
.httpBasic(basic -> basic.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/accounts/signup").permitAll()
.requestMatchers("/api/accounts/signup", "/api/accounts/login", "/").permitAll()
.anyRequest().authenticated()
);
)
.addFilterAt(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(
exceptionHandlingConfigurer -> exceptionHandlingConfigurer.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")));

return http.build();
}
Expand All @@ -30,4 +54,32 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(customUserDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}

@Bean
public AuthenticationManager authenticationManager(DaoAuthenticationProvider authenticationProvider) {
return new ProviderManager(authenticationProvider);
}

@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(AuthenticationManager authenticationManager) {
JwtAuthenticationFilter filter = new JwtAuthenticationFilter(authenticationManager, objectMapper);

filter.setFilterProcessesUrl("/api/accounts/login");
filter.setAuthenticationSuccessHandler(loginSuccessHandler);
filter.setAuthenticationFailureHandler(loginFailureHandler);

return filter;
}

@Bean
public GrantedAuthoritiesMapper customAuthorityMapper() {
return new CustomAuthorityMapper();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.synapse.account_service.convert;

import com.synapse.account_service.domain.Member;

public record ProviderUserRequest(Member member) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.synapse.account_service.convert.authority;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;

public class CustomAuthorityMapper implements GrantedAuthoritiesMapper {

private final String PREFIX = "ROLE_";

@Override
public Set<GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
HashSet<GrantedAuthority> mapped = new HashSet<>(authorities.size());
for (GrantedAuthority authority : authorities) {
mapped.add(mapAuthority(authority.getAuthority()));
}

return mapped;
}

private GrantedAuthority mapAuthority(String name) {
if (!name.startsWith(PREFIX)) {
name = PREFIX + name;
}
return new SimpleGrantedAuthority(name);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.synapse.account_service.domain;

import java.util.UUID;

import org.springframework.security.crypto.password.PasswordEncoder;

import com.synapse.account_service.common.BaseEntity;
Expand All @@ -17,9 +19,9 @@
@Table(name = "members")
public class Member extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.UUID)
@Column(name = "member_id")
private Long id;
private UUID id;

@Column(name = "username", nullable = false)
private String username;
Expand Down Expand Up @@ -47,7 +49,8 @@ public class Member extends BaseEntity {
private Subscription subscription;

@Builder
public Member(String username, String password, String email, String provider, String picture, String registrationId, MemberRole role) {
public Member(UUID id, String username, String password, String email, String provider, String picture, String registrationId, MemberRole role) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.synapse.account_service.domain;

import java.util.Collection;
import java.util.Map;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;

public record PrincipalUser(ProviderUser providerUser) implements UserDetails, OidcUser {

@Override
public String getName() {
return providerUser.getUsername();
}

@Override
public Map<String, Object> getAttributes() {
return providerUser.getAttributes();
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return providerUser.getAuthorities();
}

@Override
public String getPassword() {
return providerUser.getPassword();
}

@Override
public String getUsername() {
return providerUser.getUsername();
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}

@Override
public Map<String, Object> getClaims() {
return null;
}

@Override
public OidcUserInfo getUserInfo() {
return null;
}

@Override
public OidcIdToken getIdToken() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.synapse.account_service.domain;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.OAuth2User;

public interface ProviderUser {
UUID getId();

String getUsername();

String getPassword();

String getEmail();

String getProvider();

String getPicture();

List<? extends GrantedAuthority> getAuthorities();

Map<String, Object> getAttributes();

OAuth2User getOAuth2User();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.synapse.account_service.domain;

import java.time.ZonedDateTime;
import java.util.UUID;

import com.synapse.account_service.common.BaseTimeEntity;
import com.synapse.account_service.domain.enums.SubscriptionTier;
Expand All @@ -14,9 +15,9 @@
@Table(name = "subscription")
public class Subscription extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.UUID)
@Column(name = "subscription_id")
private Long id;
private UUID id;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package com.synapse.account_service.domain.enums;

import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

public enum MemberRole {
USER, ADMIN
USER, ADMIN;

public List<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(this.name()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.synapse.account_service.domain.forms;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.OAuth2User;

import com.synapse.account_service.domain.ProviderUser;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class FormUser implements ProviderUser {

private String registrationId;
private UUID id;
private String username;
private String password;
private String email;
private String provider;
private List<? extends GrantedAuthority> authorities;

@Override
public UUID getId() {
return id;
}

@Override
public String getUsername() {
return username;
}

@Override
public String getPassword() {
return password;
}

@Override
public String getEmail() {
return email;
}

@Override
public String getProvider() {
return provider;
}

@Override
public String getPicture() {
return null;
}

@Override
public List<? extends GrantedAuthority> getAuthorities() {
return authorities;
}

@Override
public Map<String, Object> getAttributes() {
return null;
}

@Override
public OAuth2User getOAuth2User() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.synapse.account_service.dto;

/**
* JwtService가 최종적으로 생성하여 반환할 인증 토큰 DTO
*
* @param accessToken 액세스 토큰 정보
* @param refreshToken 리프레시 토큰 정보
*/
public record TokenResponse(TokenResult accessToken, TokenResult refreshToken) {

}
Loading
Loading