--- build.gradle
+++ build.gradle
... | ... | @@ -57,6 +57,18 @@ |
57 | 57 |
// log4jdbc |
58 | 58 |
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4:1.16' |
59 | 59 |
|
60 |
+ //JWT |
|
61 |
+ implementation 'io.jsonwebtoken:jjwt-api:0.12.5' |
|
62 |
+ implementation 'io.jsonwebtoken:jjwt-impl:0.12.5' |
|
63 |
+ implementation 'io.jsonwebtoken:jjwt-jackson:0.12.5' |
|
64 |
+ |
|
65 |
+ // redis |
|
66 |
+ implementation 'org.springframework.boot:spring-boot-starter-data-redis' |
|
67 |
+ implementation 'org.springframework.boot:spring-boot-starter-cache' |
|
68 |
+ |
|
69 |
+ // gson |
|
70 |
+ implementation 'com.google.code.gson:gson:2.10.1' |
|
71 |
+ |
|
60 | 72 |
} |
61 | 73 |
|
62 | 74 |
tasks.named('test') { |
--- src/main/java/com/takensoft/sj_wmp/common/confing/SecurityConfig.java
+++ src/main/java/com/takensoft/sj_wmp/common/confing/SecurityConfig.java
... | ... | @@ -1,22 +1,96 @@ |
1 | 1 |
package com.takensoft.sj_wmp.common.confing; |
2 | 2 |
|
3 |
+import com.takensoft.sj_wmp.common.filter.JwtFilter; |
|
4 |
+import com.takensoft.sj_wmp.common.filter.LoginFilter; |
|
5 |
+import com.takensoft.sj_wmp.common.util.JwtUtil; |
|
6 |
+import org.springframework.beans.factory.annotation.Value; |
|
3 | 7 |
import org.springframework.context.annotation.Bean; |
4 | 8 |
import org.springframework.context.annotation.Configuration; |
9 |
+import org.springframework.security.authentication.AuthenticationManager; |
|
10 |
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; |
|
5 | 11 |
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
6 | 12 |
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
13 |
+import org.springframework.security.config.http.SessionCreationPolicy; |
|
14 |
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|
7 | 15 |
import org.springframework.security.web.SecurityFilterChain; |
16 |
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
|
17 |
+import org.springframework.web.cors.CorsConfiguration; |
|
18 |
+import org.springframework.web.cors.CorsConfigurationSource; |
|
19 |
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
|
20 |
+ |
|
21 |
+import java.util.Collections; |
|
22 |
+import java.util.List; |
|
8 | 23 |
|
9 | 24 |
@Configuration |
10 | 25 |
@EnableWebSecurity |
11 | 26 |
public class SecurityConfig { |
12 | 27 |
|
28 |
+ private final AuthenticationConfiguration authenticationConfiguration; |
|
29 |
+ private final JwtUtil jwtUtil; |
|
30 |
+ private final CommonConfig commonConfig; |
|
31 |
+ |
|
32 |
+ private static String FRONT_URL; // 프론트 경로 |
|
33 |
+ private static long JWT_ACCESSTIME; // access 토큰 유지 시간 |
|
34 |
+ private static int COOKIE_TIME; // 쿠키 유지 시간 |
|
35 |
+ |
|
36 |
+ public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JwtUtil jwtUtil, CommonConfig commonConfig, |
|
37 |
+ @Value("${frontUrl}") String fUrl, @Value("${spring.jwt.accessTime}") long aTime, @Value("${spring.jwt.refreshTime}") long rTime, @Value("${cookie.time}") int ctime |
|
38 |
+ ) { |
|
39 |
+ this.authenticationConfiguration = authenticationConfiguration; |
|
40 |
+ this.jwtUtil = jwtUtil; |
|
41 |
+ this.commonConfig = commonConfig; |
|
42 |
+ |
|
43 |
+ this.FRONT_URL = fUrl; |
|
44 |
+ this.JWT_ACCESSTIME = aTime; |
|
45 |
+ this.COOKIE_TIME = ctime; |
|
46 |
+ } |
|
47 |
+ |
|
48 |
+ // AuthenticationManager Bean 등록 |
|
49 |
+ @Bean |
|
50 |
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { |
|
51 |
+ return configuration.getAuthenticationManager(); |
|
52 |
+ } |
|
53 |
+ |
|
13 | 54 |
@Bean |
14 | 55 |
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { |
15 |
- http.csrf((auth) -> auth.disable()); |
|
56 |
+ http.csrf((auth) -> auth.disable()); // CSRF 비활성화 |
|
57 |
+ http.formLogin((auth) -> auth.disable()); // 폼 로그인 비활성화 |
|
58 |
+ http.httpBasic((auth) -> auth.disable()); // HTTP Basic 비활성화 |
|
59 |
+ http.sessionManagement((auth) -> auth.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // 세션 비활성화 |
|
60 |
+ http.cors((auth) -> auth.configurationSource(corsConfigurationSource())); // CORS 설정 |
|
61 |
+ http.authorizeHttpRequests((auth) -> auth |
|
62 |
+ .requestMatchers( "/auth/**", "/auth/login.json").permitAll() // /user/** 경로는 모두 허용 |
|
63 |
+ .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() // swagger 진입 허용 |
|
64 |
+ .anyRequest().authenticated()); // 나머지 경로는 인증 필요 |
|
65 |
+ |
|
66 |
+ // jwt 필터 처리 적용 |
|
67 |
+ http.addFilterBefore(new JwtFilter(jwtUtil, commonConfig), LoginFilter.class); // 토큰 검증 필터 |
|
68 |
+ http.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil, commonConfig, JWT_ACCESSTIME), UsernamePasswordAuthenticationFilter.class); |
|
16 | 69 |
|
17 | 70 |
return http.build(); |
18 | 71 |
} |
19 | 72 |
|
73 |
+ // 패스워드 암호화 |
|
74 |
+ @Bean |
|
75 |
+ public BCryptPasswordEncoder bCryptPasswordEncoder() { |
|
76 |
+ return new BCryptPasswordEncoder(); |
|
77 |
+ } |
|
78 |
+ |
|
79 |
+ // CORS 설정 |
|
80 |
+ @Bean |
|
81 |
+ public CorsConfigurationSource corsConfigurationSource() { |
|
82 |
+ CorsConfiguration configuration = new CorsConfiguration(); |
|
83 |
+ configuration.setAllowedOrigins(Collections.singletonList(FRONT_URL)); |
|
84 |
+ configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")); |
|
85 |
+ configuration.setAllowedHeaders(List.of("*")); |
|
86 |
+ configuration.setExposedHeaders(Collections.singletonList("Authorization")); |
|
87 |
+ |
|
88 |
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
|
89 |
+ source.registerCorsConfiguration("/**", configuration); |
|
90 |
+ |
|
91 |
+ return source; |
|
92 |
+ } |
|
93 |
+ |
|
20 | 94 |
// inmemory방식 유저 설정 |
21 | 95 |
// @Bean |
22 | 96 |
// public InMemoryUserDetailsManager userDetailsService() { |
--- src/main/java/com/takensoft/sj_wmp/common/confing/SwaggerConfig.java
+++ src/main/java/com/takensoft/sj_wmp/common/confing/SwaggerConfig.java
... | ... | @@ -3,15 +3,31 @@ |
3 | 3 |
import io.swagger.v3.oas.models.Components; |
4 | 4 |
import io.swagger.v3.oas.models.OpenAPI; |
5 | 5 |
import io.swagger.v3.oas.models.info.Info; |
6 |
+import io.swagger.v3.oas.models.security.SecurityRequirement; |
|
7 |
+import io.swagger.v3.oas.models.security.SecurityScheme; |
|
6 | 8 |
import org.springframework.context.annotation.Bean; |
7 | 9 |
import org.springframework.context.annotation.Configuration; |
8 | 10 |
|
9 | 11 |
@Configuration |
10 | 12 |
public class SwaggerConfig { |
11 | 13 |
@Bean |
12 |
- public OpenAPI openAPI() { |
|
14 |
+ public OpenAPI api() { |
|
15 |
+ // SecurityScheme 설정 |
|
16 |
+ SecurityScheme apiKey = new SecurityScheme() |
|
17 |
+ .type(SecurityScheme.Type.HTTP) |
|
18 |
+ .in(SecurityScheme.In.HEADER) |
|
19 |
+ .name("Authorization") |
|
20 |
+ .scheme("bearer") |
|
21 |
+ .bearerFormat("JWT"); |
|
22 |
+ |
|
23 |
+ // SecurityRequirement 설정 |
|
24 |
+ SecurityRequirement securityRequirement = new SecurityRequirement() |
|
25 |
+ .addList("Bearer Token"); |
|
26 |
+ |
|
27 |
+ // OpenAPI 설정 |
|
13 | 28 |
return new OpenAPI() |
14 |
- .components(new Components()) |
|
29 |
+ .components(new Components().addSecuritySchemes("Bearer Token", apiKey)) |
|
30 |
+ .addSecurityItem(securityRequirement) |
|
15 | 31 |
.info(apiInfo()); |
16 | 32 |
} |
17 | 33 |
private Info apiInfo() { |
+++ src/main/java/com/takensoft/sj_wmp/common/filter/JwtFilter.java
... | ... | @@ -0,0 +1,85 @@ |
1 | +package com.takensoft.sj_wmp.common.filter; | |
2 | + | |
3 | +import com.takensoft.sj_wmp.common.confing.CommonConfig; | |
4 | +import com.takensoft.sj_wmp.common.util.ErrorResponse; | |
5 | +import com.takensoft.sj_wmp.common.util.JwtUtil; | |
6 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserAuthorVO; | |
7 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
8 | +import io.jsonwebtoken.ExpiredJwtException; | |
9 | +import io.jsonwebtoken.JwtException; | |
10 | +import jakarta.servlet.FilterChain; | |
11 | +import jakarta.servlet.http.HttpServletRequest; | |
12 | +import jakarta.servlet.http.HttpServletResponse; | |
13 | +import lombok.RequiredArgsConstructor; | |
14 | +import org.springframework.http.HttpStatus; | |
15 | +import org.springframework.http.MediaType; | |
16 | +import org.springframework.security.authentication.InsufficientAuthenticationException; | |
17 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
18 | +import org.springframework.security.core.Authentication; | |
19 | +import org.springframework.security.core.context.SecurityContextHolder; | |
20 | +import org.springframework.stereotype.Component; | |
21 | +import org.springframework.web.filter.OncePerRequestFilter; | |
22 | + | |
23 | +import java.io.IOException; | |
24 | +import java.time.LocalDateTime; | |
25 | +import java.util.List; | |
26 | + | |
27 | +@Component | |
28 | +@RequiredArgsConstructor | |
29 | +public class JwtFilter extends OncePerRequestFilter { | |
30 | + | |
31 | + private final JwtUtil jwtUtil; | |
32 | + private final CommonConfig commonConfig; | |
33 | + | |
34 | + @Override | |
35 | + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws jakarta.servlet.ServletException, IOException { | |
36 | + // 헤더에서 access에 대한 토큰을 꺼냄 | |
37 | + String accessToken = request.getHeader("Authorization"); | |
38 | + // 토큰이 없다면 다음 필터로 넘김 | |
39 | + if (accessToken == null) { | |
40 | + filterChain.doFilter(request, response); | |
41 | + return; | |
42 | + } | |
43 | + try { | |
44 | + // 토큰 만료 여부 검증 | |
45 | + if (jwtUtil.isExpired(accessToken)) { | |
46 | + throw new JwtException("Token expired"); | |
47 | + } | |
48 | + // 토큰에서 페이로드 확인[ 발급시 명시 ] | |
49 | + String category = jwtUtil.getCategory(accessToken); | |
50 | + if (!category.equals("Authorization")) { | |
51 | + throw new JwtException("Wrong Token"); | |
52 | + } | |
53 | + // 토큰에서 사용자 정보 추출 | |
54 | + UserVO user = new UserVO(); | |
55 | + List<UserAuthorVO> author = jwtUtil.getRoles(accessToken); | |
56 | + user.setLoginId(jwtUtil.getLoginId(accessToken)); | |
57 | + user.setUsid(jwtUtil.getUsid(accessToken)); | |
58 | + user.setAuthor(author); | |
59 | + | |
60 | + // 시큐리티 컨텍스트에 사용자 정보 설정 | |
61 | + Authentication authToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); | |
62 | + SecurityContextHolder.getContext().setAuthentication(authToken); | |
63 | + // 다음 필터로 이동 | |
64 | + filterChain.doFilter(request, response); | |
65 | + } catch (JwtException | InsufficientAuthenticationException e) { | |
66 | + // 토큰 검증 실패 시 클라이언트에게 에러 응답을 위한 객체 생성 | |
67 | + ErrorResponse errorResponse = new ErrorResponse(); | |
68 | + // 에러 응답 메시지 설정 | |
69 | + if (e instanceof ExpiredJwtException) { | |
70 | + errorResponse.setMessage("Token expired"); | |
71 | + } else { | |
72 | + errorResponse.setMessage(e.getMessage()); | |
73 | + } | |
74 | + errorResponse.setPath(request.getRequestURI()); // 오류 경로 설정 | |
75 | + errorResponse.setError(HttpStatus.UNAUTHORIZED.getReasonPhrase()); // 오류 원인 설정 | |
76 | + errorResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); // 상태코드 설정 | |
77 | + errorResponse.setTimestamp(LocalDateTime.now()); // 응답 시간 설정 | |
78 | + | |
79 | + // 응답 헤더 설정 및 json 응답 전송 | |
80 | + response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
81 | + response.setStatus(HttpStatus.UNAUTHORIZED.value()); | |
82 | + response.getOutputStream().write(commonConfig.getObjectMapper().writeValueAsBytes(errorResponse)); | |
83 | + } | |
84 | + } | |
85 | +} |
+++ src/main/java/com/takensoft/sj_wmp/common/filter/LoginFilter.java
... | ... | @@ -0,0 +1,97 @@ |
1 | +package com.takensoft.sj_wmp.common.filter; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import com.takensoft.sj_wmp.common.confing.CommonConfig; | |
5 | +import com.takensoft.sj_wmp.common.util.JwtUtil; | |
6 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
7 | +import jakarta.servlet.FilterChain; | |
8 | +import jakarta.servlet.http.HttpServletRequest; | |
9 | +import jakarta.servlet.http.HttpServletResponse; | |
10 | +import org.springframework.beans.factory.annotation.Value; | |
11 | +import org.springframework.http.HttpStatus; | |
12 | +import org.springframework.http.MediaType; | |
13 | +import org.springframework.security.authentication.AuthenticationManager; | |
14 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
15 | +import org.springframework.security.core.Authentication; | |
16 | +import org.springframework.security.core.AuthenticationException; | |
17 | +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | |
18 | + | |
19 | + | |
20 | +import java.io.IOException; | |
21 | +import java.util.HashMap; | |
22 | +import java.util.List; | |
23 | +import java.util.Map; | |
24 | + | |
25 | +public class LoginFilter extends UsernamePasswordAuthenticationFilter{ | |
26 | + | |
27 | + private final AuthenticationManager authenticationManager; | |
28 | + private final JwtUtil jwtUtil; | |
29 | + private final CommonConfig commonConfig; | |
30 | + | |
31 | + private static long JWT_ACCESSTIME; // access 토큰 유지 시간 | |
32 | + | |
33 | + public LoginFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil, CommonConfig commonConfig, @Value("${spring.jwt.accessTime}") long jwtAccesstime) { | |
34 | + this.authenticationManager = authenticationManager; | |
35 | + this.jwtUtil = jwtUtil; | |
36 | + this.commonConfig = commonConfig; | |
37 | + | |
38 | + this.JWT_ACCESSTIME = jwtAccesstime; | |
39 | + | |
40 | + setFilterProcessesUrl("/auth/login.json"); | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * 로그인 검증 | |
45 | + */ | |
46 | + @Override | |
47 | + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { | |
48 | + try { | |
49 | + Map<String, String> loginData = new ObjectMapper().readValue(request.getInputStream(), Map.class); | |
50 | + String loginId = loginData.get("loginId"); | |
51 | + String password = loginData.get("password"); | |
52 | + | |
53 | + UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginId, password); | |
54 | + return authenticationManager.authenticate(authToken); | |
55 | + } catch (IOException e) { | |
56 | + throw new RuntimeException("Failed to parse authentication request body", e); | |
57 | + } | |
58 | + } | |
59 | + | |
60 | + // 인증 성공 시 | |
61 | + @Override | |
62 | + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException { | |
63 | + response.setStatus(HttpServletResponse.SC_OK); | |
64 | + response.setContentType("application/json;charset=UTF-8"); | |
65 | + | |
66 | + UserVO user = (UserVO) authResult.getPrincipal(); | |
67 | + String usid = user.getUsid(); | |
68 | + String loginId = user.getUsername(); | |
69 | + String userNm = user.getUserNm(); | |
70 | + List<String> author = (List) user.getAuthorities(); | |
71 | + | |
72 | + String accessToken = jwtUtil.createJwt("Authorization", usid, loginId, userNm, author, JWT_ACCESSTIME); | |
73 | + | |
74 | + Map<String, Object> resData = new HashMap<>(); | |
75 | + resData.put("result", "success"); | |
76 | + resData.put("message", "로그인 성공"); | |
77 | + | |
78 | + // 헤더 방식 | |
79 | + response.setHeader("Authorization", accessToken); | |
80 | + | |
81 | + response.getWriter().write(new ObjectMapper().writeValueAsString(resData)); | |
82 | + } | |
83 | + | |
84 | + // 인증 실패 시 | |
85 | + @Override | |
86 | + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { | |
87 | + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); | |
88 | + response.setContentType("application/json;charset=UTF-8"); | |
89 | + | |
90 | + Map<String, String> responseData = new HashMap<>(); | |
91 | + responseData.put("message", "Authentication failed: " + failed.getMessage()); | |
92 | + | |
93 | + response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
94 | + response.setStatus(HttpStatus.UNAUTHORIZED.value()); | |
95 | + response.getWriter().write(commonConfig.getObjectMapper().writeValueAsString(responseData)); | |
96 | + } | |
97 | +} |
+++ src/main/java/com/takensoft/sj_wmp/common/idgen/context/ContextIdgen.java
... | ... | @@ -0,0 +1,57 @@ |
1 | +package com.takensoft.sj_wmp.common.idgen.context; | |
2 | + | |
3 | + | |
4 | +import com.takensoft.sj_wmp.common.idgen.service.IdgenService; | |
5 | +import org.springframework.context.annotation.Bean; | |
6 | +import org.springframework.context.annotation.Configuration; | |
7 | + | |
8 | +@Configuration | |
9 | +public class ContextIdgen { | |
10 | + | |
11 | + // 회원정보 | |
12 | + @Bean(name = "userIdgn") | |
13 | + public IdgenService user() { | |
14 | + IdgenService idgenServiceImpl = new IdgenService(); | |
15 | + idgenServiceImpl.setCipers(15); | |
16 | + idgenServiceImpl.setFillChar('0'); | |
17 | + idgenServiceImpl.setPrefix("USID_"); | |
18 | + idgenServiceImpl.setTblNm("USID"); | |
19 | + return idgenServiceImpl; | |
20 | + } | |
21 | + | |
22 | + // 위원 정보 | |
23 | + @Bean(name = "mfcmmIdgn") | |
24 | + public IdgenService mfcmm() { | |
25 | + IdgenService idgenServiceImpl = new IdgenService(); | |
26 | + idgenServiceImpl.setCipers(15); | |
27 | + idgenServiceImpl.setFillChar('0'); | |
28 | + idgenServiceImpl.setPrefix("MFEMM_"); | |
29 | + idgenServiceImpl.setTblNm("MFEMM_ID"); | |
30 | + return idgenServiceImpl; | |
31 | + } | |
32 | + | |
33 | + // 위원회 정보 | |
34 | + @Bean(name = "cmitIdgn") | |
35 | + public IdgenService cmit() { | |
36 | + IdgenService idgenServiceImpl = new IdgenService(); | |
37 | + idgenServiceImpl.setCipers(15); | |
38 | + idgenServiceImpl.setFillChar('0'); | |
39 | + idgenServiceImpl.setPrefix("CMIT_"); | |
40 | + idgenServiceImpl.setTblNm("CMIT_ID"); | |
41 | + return idgenServiceImpl; | |
42 | + } | |
43 | + | |
44 | + // 파일매니저 | |
45 | + @Bean(name = "fileMngIdgn") | |
46 | + public IdgenService fileMng() { | |
47 | + IdgenService idgenServiceImpl = new IdgenService(); | |
48 | + idgenServiceImpl.setCipers(15); | |
49 | + idgenServiceImpl.setFillChar('0'); | |
50 | + idgenServiceImpl.setPrefix("FILE_MNG_"); | |
51 | + idgenServiceImpl.setTblNm("FILE_MANAGE_ID"); | |
52 | + return idgenServiceImpl; | |
53 | + } | |
54 | + | |
55 | + | |
56 | + | |
57 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/java/com/takensoft/sj_wmp/common/idgen/dao/IdgenMapper.java
... | ... | @@ -0,0 +1,30 @@ |
1 | +package com.takensoft.sj_wmp.common.idgen.dao; | |
2 | + | |
3 | + | |
4 | +import com.takensoft.sj_wmp.common.idgen.vo.IdgenVO; | |
5 | +import org.egovframe.rte.psl.dataaccess.mapper.Mapper; | |
6 | + | |
7 | +/** | |
8 | + * @author :takensoft | |
9 | + * @since : 2024.04.01 | |
10 | + * | |
11 | + * Idgen 관련 Mapper | |
12 | + */ | |
13 | +@Mapper | |
14 | +public interface IdgenMapper { | |
15 | + | |
16 | + /** | |
17 | + * 테이블명으로 시퀀스 조회 | |
18 | + * @author takensoft | |
19 | + * @since 2024.04.01 | |
20 | + */ | |
21 | + IdgenVO selectNextId(String tblNm); | |
22 | + | |
23 | + /** | |
24 | + * 시퀀스 등록 및 수정 | |
25 | + * @author takensoft | |
26 | + * @since 2024.04.01 | |
27 | + */ | |
28 | + void upsertSeqNmg(IdgenVO idgenVO); | |
29 | + | |
30 | +} |
+++ src/main/java/com/takensoft/sj_wmp/common/idgen/service/IdgenService.java
... | ... | @@ -0,0 +1,52 @@ |
1 | +package com.takensoft.sj_wmp.common.idgen.service; | |
2 | + | |
3 | + | |
4 | +import com.takensoft.sj_wmp.common.idgen.dao.IdgenMapper; | |
5 | +import com.takensoft.sj_wmp.common.idgen.vo.IdgenVO; | |
6 | +import lombok.Getter; | |
7 | +import lombok.Setter; | |
8 | +import org.apache.commons.logging.Log; | |
9 | +import org.apache.commons.logging.LogFactory; | |
10 | +import org.springframework.beans.factory.annotation.Autowired; | |
11 | + | |
12 | +@Setter | |
13 | +@Getter | |
14 | +public class IdgenService { | |
15 | + | |
16 | + protected Log log = LogFactory.getLog(this.getClass()); | |
17 | + private String prefix; // 아이디에 고정적으로 붙일 명칭 | |
18 | + private int cipers; // 고정적인 명칭(prefix)를 제외한 아이디의 길이 | |
19 | + private char fillChar; // 0 | |
20 | + private String tblNm; // 테이블명 | |
21 | + | |
22 | + @Autowired | |
23 | + private IdgenMapper idgenMapper; | |
24 | + | |
25 | + public String getNextStringId() { | |
26 | + IdgenVO idgenVO = idgenMapper.selectNextId(tblNm); // 다음 아이디값 조회 | |
27 | + boolean firstFlag = false; // 신규 생성인지 확인 | |
28 | + if(idgenVO == null) { // 신규 생성일 경우 | |
29 | + idgenVO = new IdgenVO(); // 신규 객체 생성 | |
30 | + idgenVO.setAftrId(1); // 신규 아이디값 설정 | |
31 | + idgenVO.setTblNm(tblNm); // 신규 테이블명 설정 | |
32 | + firstFlag = true; // 신규 등록 여부 | |
33 | + } | |
34 | + // 1. 아이디변수 생성(String) | |
35 | + // 2. 아이디 변수 prefix를 넣고 + fillChar를 cipers-prefix.length-id.length 만큼 넣고 + (id + 1)를 넣는다. | |
36 | + String nextId = ""; // 아이디값 객체 생성 | |
37 | + nextId = prefix; // prefix 설정 | |
38 | + // 2번째부터는 1씩 업데이트 | |
39 | + if(!firstFlag) { // 기존에 데이터가 존재하는 경우 | |
40 | + idgenVO.setTblNm(tblNm); | |
41 | + idgenVO.setAftrId(idgenVO.getAftrId() + 1); | |
42 | + } | |
43 | + idgenMapper.upsertSeqNmg(idgenVO); // 아이디값을 1추가하여 데이터 수정 | |
44 | + int fillCharSize = cipers - (int)(Math.log10(idgenVO.getAftrId()) + 1); // 아이디에 0이 들어갈 길이 지정 | |
45 | + for(int i = 0 ; i < fillCharSize; i++) { // 아이디에 0 설정 | |
46 | + nextId = nextId + fillChar; // ex_ TEST_00 + 0 0이 추가되는중 | |
47 | + } | |
48 | + nextId = nextId + String.valueOf(idgenVO.getAftrId()); // 아이디 생성 완료 | |
49 | + return nextId; | |
50 | + } | |
51 | + | |
52 | +} |
+++ src/main/java/com/takensoft/sj_wmp/common/idgen/vo/IdgenVO.java
... | ... | @@ -0,0 +1,18 @@ |
1 | +package com.takensoft.sj_wmp.common.idgen.vo; | |
2 | + | |
3 | +import lombok.Getter; | |
4 | +import lombok.NoArgsConstructor; | |
5 | +import lombok.Setter; | |
6 | + | |
7 | +import java.io.Serializable; | |
8 | + | |
9 | +@SuppressWarnings("serial") | |
10 | +@NoArgsConstructor | |
11 | +@Getter | |
12 | +@Setter | |
13 | +public class IdgenVO implements Serializable { | |
14 | + // 테이블 이름 | |
15 | + private String tblNm; | |
16 | + // 다음 아이디 | |
17 | + private int aftrId; | |
18 | +} |
+++ src/main/java/com/takensoft/sj_wmp/common/util/ErrorResponse.java
... | ... | @@ -0,0 +1,24 @@ |
1 | +package com.takensoft.sj_wmp.common.util; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | |
4 | +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; | |
5 | +import lombok.Getter; | |
6 | +import lombok.Setter; | |
7 | + | |
8 | +import java.time.LocalDateTime; | |
9 | +import java.util.ArrayList; | |
10 | +import java.util.List; | |
11 | + | |
12 | +@Getter | |
13 | +@Setter | |
14 | +public class ErrorResponse { | |
15 | + | |
16 | + int status; | |
17 | + String error; | |
18 | + String message; | |
19 | + String path; | |
20 | + | |
21 | + @JsonDeserialize(using = LocalDateTimeDeserializer.class) | |
22 | + LocalDateTime timestamp; | |
23 | + List<Error> errorList = new ArrayList<Error>(); | |
24 | +} |
+++ src/main/java/com/takensoft/sj_wmp/common/util/JwtUtil.java
... | ... | @@ -0,0 +1,92 @@ |
1 | +package com.takensoft.sj_wmp.common.util; | |
2 | + | |
3 | +import com.takensoft.sj_wmp.wmp.auth.vo.AuthVO; | |
4 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserAuthorVO; | |
5 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
6 | +import io.jsonwebtoken.Claims; | |
7 | +import io.jsonwebtoken.Jwts; | |
8 | +import jakarta.servlet.http.Cookie; | |
9 | +import org.springframework.beans.factory.annotation.Value; | |
10 | +import org.springframework.security.core.Authentication; | |
11 | +import org.springframework.security.core.context.SecurityContextHolder; | |
12 | +import org.springframework.security.core.userdetails.UserDetails; | |
13 | +import org.springframework.stereotype.Component; | |
14 | + | |
15 | +import javax.crypto.SecretKey; | |
16 | +import javax.crypto.spec.SecretKeySpec; | |
17 | +import java.nio.charset.StandardCharsets; | |
18 | +import java.util.*; | |
19 | + | |
20 | +@Component | |
21 | +public class JwtUtil { | |
22 | + | |
23 | + private SecretKey secretKey; | |
24 | + | |
25 | + public JwtUtil(@Value("${spring.jwt.secret}") String secret) { | |
26 | + this.secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); | |
27 | + } | |
28 | + | |
29 | + // 토큰 생성 메서드 | |
30 | + public String createJwt(String category, String usid, String loginId, String userNm, List<String> author, long expiredMs) { | |
31 | + | |
32 | + return Jwts.builder() | |
33 | + .claim("category", category) | |
34 | + .claim("usid", usid) | |
35 | + .claim("loginId", loginId) | |
36 | + .claim("userNm", userNm) | |
37 | + .claim("author", author) | |
38 | + .issuedAt(new Date(System.currentTimeMillis())) | |
39 | + .expiration(new Date(System.currentTimeMillis() + expiredMs)) | |
40 | + .signWith(secretKey) | |
41 | + .compact(); | |
42 | + } | |
43 | + public String getCategory(String token) { | |
44 | + return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("category", String.class); | |
45 | + } | |
46 | + | |
47 | + // 아이디 반환 메서드 | |
48 | + public String getUsid(String token) { | |
49 | + return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("usid", String.class); | |
50 | + } | |
51 | + // 사용자 아이디 반환 메서드 | |
52 | + public String getLoginId(String token) { | |
53 | + return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("loginId", String.class); | |
54 | + } | |
55 | + // 사용자 이름 반환 메서드 | |
56 | + public String getUserNm(String token) { | |
57 | + return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("userNm", String.class); | |
58 | + } | |
59 | + // 접속자 토큰 기반 권한정보 추출 | |
60 | + public List<UserAuthorVO> getRoles(String token) { | |
61 | + // 토큰에서 권한 정보를 가져옴 | |
62 | + Claims claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload(); | |
63 | + List<HashMap> roles = claims.get("author", List.class); | |
64 | + List<UserAuthorVO> authorList = new ArrayList<>(); | |
65 | + if (roles != null && !roles.isEmpty()) { | |
66 | + for(Map role : roles) { | |
67 | + UserAuthorVO mberAuthor = new UserAuthorVO(); | |
68 | + mberAuthor.setAuthorCode(role.get("authority").toString()); | |
69 | + authorList.add(mberAuthor); | |
70 | + } | |
71 | + } | |
72 | + System.out.println("authorList : " + authorList); | |
73 | + return authorList; | |
74 | + } | |
75 | + | |
76 | + // 토큰 소멸 여부 | |
77 | + public Boolean isExpired(String token) { | |
78 | + return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().getExpiration().before(new Date()); | |
79 | + } | |
80 | + | |
81 | + // 로그인 사용자 아이디 조회 | |
82 | + public String getWriter() { | |
83 | + String loginId = null; | |
84 | + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | |
85 | + if(authentication != null && authentication.isAuthenticated()) { | |
86 | + Object principal = authentication.getPrincipal(); | |
87 | + if(principal instanceof UserDetails) loginId = ((UserVO) authentication.getPrincipal()).getLoginId(); | |
88 | + } | |
89 | + return loginId; | |
90 | + } | |
91 | + | |
92 | +} |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/dao/AuthDAO.java
... | ... | @@ -0,0 +1,24 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.dao; | |
2 | + | |
3 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
4 | +import org.egovframe.rte.psl.dataaccess.mapper.Mapper; | |
5 | +import org.springframework.security.core.userdetails.UserDetails; | |
6 | +import org.springframework.security.core.userdetails.UsernameNotFoundException; | |
7 | + | |
8 | +import java.util.Map; | |
9 | + | |
10 | +/** | |
11 | + * @author : 방선주 | |
12 | + * @since : 2024.07.12 | |
13 | + * | |
14 | + * 사용자 관련 Mapper | |
15 | + */ | |
16 | +@Mapper("authDAO") | |
17 | +public interface AuthDAO { | |
18 | + int insertUser(UserVO userVO) throws Exception; | |
19 | + | |
20 | + UserDetails findByUserIdSecurity(String loginId) throws UsernameNotFoundException; | |
21 | + | |
22 | + int insertAuth(Map<String, Object> authMap) throws Exception; | |
23 | +} | |
24 | + |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/dto/LoginDTO.java
... | ... | @@ -0,0 +1,35 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.dto; | |
2 | + | |
3 | +import lombok.AllArgsConstructor; | |
4 | +import lombok.Builder; | |
5 | +import lombok.Data; | |
6 | +import lombok.NoArgsConstructor; | |
7 | + | |
8 | +import javax.validation.constraints.NotNull; | |
9 | + | |
10 | +/** | |
11 | + * @author : takensoft | |
12 | + * @since : 2024.04.01 | |
13 | + * | |
14 | + * 로그인 관련 DTO | |
15 | + */ | |
16 | +@Data | |
17 | +@AllArgsConstructor | |
18 | +@NoArgsConstructor | |
19 | +@Builder | |
20 | +public class LoginDTO { | |
21 | + /** | |
22 | + * 로그인 아이디 | |
23 | + */ | |
24 | + @NotNull | |
25 | + private String loginId; | |
26 | + /** | |
27 | + * 비밀번호 | |
28 | + */ | |
29 | + @NotNull | |
30 | + private String password; | |
31 | + /** | |
32 | + * refreshToken 정보 | |
33 | + */ | |
34 | + private String refreshToken; | |
35 | +} |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/service/AuthService.java
... | ... | @@ -0,0 +1,13 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.service; | |
2 | + | |
3 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
4 | + | |
5 | +/** | |
6 | + * @author : 방선주 | |
7 | + * since : 2024.07.12 | |
8 | + * | |
9 | + * 인증 관련 인터페이스 | |
10 | + */ | |
11 | +public interface AuthService { | |
12 | + int insertUser(UserVO userVO) throws Exception; | |
13 | +} |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/service/Impl/AuthServiceImpl.java
... | ... | @@ -0,0 +1,79 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.service.Impl; | |
2 | + | |
3 | +import com.takensoft.sj_wmp.common.idgen.service.IdgenService; | |
4 | +import com.takensoft.sj_wmp.common.util.JwtUtil; | |
5 | +import com.takensoft.sj_wmp.wmp.auth.dao.AuthDAO; | |
6 | +import com.takensoft.sj_wmp.wmp.auth.service.AuthService; | |
7 | +import com.takensoft.sj_wmp.wmp.auth.vo.AuthVO; | |
8 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
9 | +import lombok.RequiredArgsConstructor; | |
10 | +import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; | |
11 | +import org.springframework.security.core.userdetails.UserDetails; | |
12 | +import org.springframework.security.core.userdetails.UserDetailsService; | |
13 | +import org.springframework.security.core.userdetails.UsernameNotFoundException; | |
14 | +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | |
15 | +import org.springframework.stereotype.Service; | |
16 | +import org.springframework.transaction.annotation.Transactional; | |
17 | + | |
18 | +import java.util.HashMap; | |
19 | +import java.util.Map; | |
20 | + | |
21 | +/** | |
22 | + * @author : 방선주 | |
23 | + * @since : 2024.07.12 | |
24 | + * 사용자 관련 구현체 | |
25 | + * EgovAbstractServiceImpl : 전자정부 상속 | |
26 | + * AuthService : 인중 인터페이스 상속 | |
27 | + */ | |
28 | +@Service("authService") | |
29 | +@RequiredArgsConstructor | |
30 | +public class AuthServiceImpl extends EgovAbstractServiceImpl implements UserDetailsService, AuthService { | |
31 | + | |
32 | + private final AuthDAO authDAO; | |
33 | + private final BCryptPasswordEncoder bCryptPasswordEncoder; | |
34 | + private final JwtUtil jwtUtil; | |
35 | + | |
36 | + private final IdgenService userIdgn; | |
37 | + | |
38 | + @Override | |
39 | + @Transactional(readOnly = true) | |
40 | + public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException { | |
41 | + return authDAO.findByUserIdSecurity(loginId); | |
42 | + } | |
43 | + | |
44 | + /** | |
45 | + * 사용자 등록 | |
46 | + */ | |
47 | + @Override | |
48 | + @Transactional | |
49 | + public int insertUser(UserVO userVO) throws Exception { | |
50 | + // TODO 동일한 계정이 있는지 확인 하는 로직 추가 | |
51 | + UserVO checkLoginId = (UserVO) authDAO.findByUserIdSecurity(userVO.getLoginId()); | |
52 | + if(checkLoginId != null) { | |
53 | + return -1; | |
54 | + } | |
55 | + String usid = userIdgn.getNextStringId(); | |
56 | + userVO.setUsid(usid); | |
57 | + | |
58 | + // 작성자 조회 및 등록 | |
59 | + if(jwtUtil.getWriter() != null && !jwtUtil.getWriter().equals("")) { | |
60 | + userVO.setReg(jwtUtil.getWriter()); | |
61 | + } | |
62 | + // 패스워드 암호화 | |
63 | + userVO.setPassword(bCryptPasswordEncoder.encode(userVO.getPassword())); | |
64 | + // 사용자 등록 | |
65 | + int result = authDAO.insertUser(userVO); | |
66 | + | |
67 | + // 권한 등록 | |
68 | + Map<String, Object> authMap = new HashMap<>(); | |
69 | + authMap.put("usid", usid); | |
70 | + authMap.put("author_code", "USER"); | |
71 | + authDAO.insertAuth(authMap); | |
72 | + | |
73 | + return result; | |
74 | + } | |
75 | + | |
76 | + | |
77 | +} | |
78 | + | |
79 | + |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/vo/AuthVO.java
... | ... | @@ -0,0 +1,32 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.vo; | |
2 | + | |
3 | +import lombok.AllArgsConstructor; | |
4 | +import lombok.Getter; | |
5 | +import lombok.NoArgsConstructor; | |
6 | +import lombok.Setter; | |
7 | + | |
8 | +import java.time.LocalDateTime; | |
9 | + | |
10 | +@Setter | |
11 | +@Getter | |
12 | +@NoArgsConstructor | |
13 | +@AllArgsConstructor | |
14 | +public class AuthVO { | |
15 | + // 권한 코드 | |
16 | + private String authorCode; | |
17 | + // 권한 명 | |
18 | + private String authorNm; | |
19 | + // 권한 설명 | |
20 | + private String authorDc; | |
21 | + // 사용 여부 | |
22 | + private String useAt; | |
23 | + // 등록자 명 | |
24 | + private String reg; | |
25 | + // 등록일자 | |
26 | + private LocalDateTime regDt; | |
27 | + // 수정자 명 | |
28 | + private String updusr; | |
29 | + // 수정일자 | |
30 | + private LocalDateTime updtDt; | |
31 | + | |
32 | +} |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/vo/UserAuthorVO.java
... | ... | @@ -0,0 +1,17 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.vo; | |
2 | + | |
3 | +import lombok.AllArgsConstructor; | |
4 | +import lombok.Getter; | |
5 | +import lombok.NoArgsConstructor; | |
6 | +import lombok.Setter; | |
7 | + | |
8 | +@Getter | |
9 | +@Setter | |
10 | +@NoArgsConstructor | |
11 | +@AllArgsConstructor | |
12 | +public class UserAuthorVO { | |
13 | + // 회원아이디 | |
14 | + private String usid; | |
15 | + // 권한 코드 | |
16 | + private String authorCode; | |
17 | +} |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/vo/UserVO.java
... | ... | @@ -0,0 +1,101 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.vo; | |
2 | + | |
3 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
4 | +import lombok.*; | |
5 | +import org.springframework.security.core.GrantedAuthority; | |
6 | +import org.springframework.security.core.authority.SimpleGrantedAuthority; | |
7 | +import org.springframework.security.core.userdetails.UserDetails; | |
8 | + | |
9 | +import java.time.LocalDate; | |
10 | +import java.time.LocalDateTime; | |
11 | +import java.util.ArrayList; | |
12 | +import java.util.Collection; | |
13 | +import java.util.List; | |
14 | +import java.util.stream.Collectors; | |
15 | + | |
16 | +/** | |
17 | + * @author : 방선주 | |
18 | + * since : 2024.05.09 | |
19 | + * | |
20 | + * 사용자 관련 VO | |
21 | + */ | |
22 | + | |
23 | +@Setter | |
24 | +@Getter | |
25 | +@ToString | |
26 | +@AllArgsConstructor | |
27 | +@NoArgsConstructor | |
28 | +public class UserVO implements UserDetails { | |
29 | + | |
30 | + // 사용자 아이디 | |
31 | + private String usid; | |
32 | + // 로그인 아이디 | |
33 | + private String loginId; | |
34 | + // 비밀번호 | |
35 | + private String password; | |
36 | + // 사용자명 | |
37 | + private String userNm; | |
38 | + // 이메일 | |
39 | + private String email; | |
40 | + // 전화번호 | |
41 | + private String telno; | |
42 | + // 계정 사용 여부 | |
43 | + private boolean useAt; | |
44 | + // 등록자 명 | |
45 | + private String reg; | |
46 | + // 등록일자 | |
47 | + private LocalDateTime registDt; | |
48 | + // 수정자 명 | |
49 | + private String updusr; | |
50 | + // 수정일자 | |
51 | + private LocalDateTime updtDt; | |
52 | + // 권한 | |
53 | + @JsonIgnore | |
54 | + private List<UserAuthorVO> author; | |
55 | + | |
56 | + // 계정이 가지곤 있는 권한 목록 리턴 | |
57 | + @Override | |
58 | + public Collection<? extends GrantedAuthority> getAuthorities() { | |
59 | + if (this.author != null) { | |
60 | + if (this.author.size() > 0) { | |
61 | + return this.author.stream().map(auth -> new SimpleGrantedAuthority( | |
62 | + auth.getAuthorCode() | |
63 | + )).collect(Collectors.toList()); | |
64 | + } else { | |
65 | + return null; | |
66 | + } | |
67 | + } | |
68 | + return null; | |
69 | + } | |
70 | + | |
71 | + // 계정의 id를 리턴 | |
72 | + @Override | |
73 | + public String getUsername() { | |
74 | + return loginId; | |
75 | + } | |
76 | + // 계정의 패스워드 리턴 | |
77 | + @Override | |
78 | + public String getPassword() { | |
79 | + return password; | |
80 | + } | |
81 | + // 계정이 만료되지 않았는지를 리턴 | |
82 | + @Override | |
83 | + public boolean isAccountNonExpired() { | |
84 | + return this.useAt; | |
85 | + } | |
86 | + // 계정이 잠겨있지 않은지를 리턴 | |
87 | + @Override | |
88 | + public boolean isAccountNonLocked() { | |
89 | + return this.useAt; | |
90 | + } | |
91 | + // 계정의 패스워드가 만료되지 않았는지 리턴 | |
92 | + @Override | |
93 | + public boolean isCredentialsNonExpired() { | |
94 | + return this.useAt; | |
95 | + } | |
96 | + // 계정이 사용가능한 계정인지를 리턴 | |
97 | + @Override | |
98 | + public boolean isEnabled() { | |
99 | + return this.useAt; | |
100 | + } | |
101 | +} |
+++ src/main/java/com/takensoft/sj_wmp/wmp/auth/web/AuthController.java
... | ... | @@ -0,0 +1,68 @@ |
1 | +package com.takensoft.sj_wmp.wmp.auth.web; | |
2 | + | |
3 | +import com.google.gson.Gson; | |
4 | +import com.google.gson.JsonObject; | |
5 | +import com.takensoft.sj_wmp.wmp.auth.service.AuthService; | |
6 | +import com.takensoft.sj_wmp.wmp.auth.vo.UserVO; | |
7 | +import io.swagger.v3.oas.annotations.Operation; | |
8 | +import lombok.RequiredArgsConstructor; | |
9 | +import lombok.extern.slf4j.Slf4j; | |
10 | +import org.springframework.http.HttpStatus; | |
11 | +import org.springframework.http.ResponseEntity; | |
12 | +import org.springframework.web.bind.annotation.PostMapping; | |
13 | +import org.springframework.web.bind.annotation.RequestBody; | |
14 | +import org.springframework.web.bind.annotation.RequestMapping; | |
15 | +import org.springframework.web.bind.annotation.RestController; | |
16 | + | |
17 | +/** | |
18 | + * @author : 방선주 | |
19 | + * since : 2024.05.09 | |
20 | + * 사용자 관련 Controller | |
21 | + */ | |
22 | +@RestController | |
23 | +@RequiredArgsConstructor | |
24 | +@Slf4j | |
25 | +@RequestMapping(value="/auth") | |
26 | +public class AuthController { | |
27 | + | |
28 | + private final AuthService authService; | |
29 | + | |
30 | + /** | |
31 | + * @author 방선주 | |
32 | + * @since 2024.07.12 | |
33 | + * param UserVO | |
34 | + * @return | |
35 | + * @throws Exception | |
36 | + * | |
37 | + * 사용자 등록 | |
38 | + */ | |
39 | + @PostMapping("/insertUser.json") | |
40 | + @Operation(summary = "사용자 등록") | |
41 | + public String insertUser(@RequestBody UserVO userVO) throws Exception { | |
42 | + Gson gson = new Gson(); | |
43 | + JsonObject response = new JsonObject(); | |
44 | + | |
45 | + try { | |
46 | + int result = authService.insertUser(userVO); | |
47 | + | |
48 | + | |
49 | + if (result == -1) { | |
50 | + response.addProperty("status", "fail"); | |
51 | + response.addProperty("message", "동일한 계정이 존재합니다."); | |
52 | + return gson.toJson(response); | |
53 | + } | |
54 | + | |
55 | + response.addProperty("status", "success"); | |
56 | + response.addProperty("message", "사용자가 등록되었습니다."); | |
57 | + return gson.toJson(response); | |
58 | + } catch (Exception e) { | |
59 | + response.addProperty("status", "error"); | |
60 | + response.addProperty("message", e.getMessage()); | |
61 | + return gson.toJson(response); | |
62 | + } | |
63 | + | |
64 | + | |
65 | + } | |
66 | + | |
67 | + | |
68 | +} |
--- src/main/resources/application.yml
+++ src/main/resources/application.yml
... | ... | @@ -2,6 +2,13 @@ |
2 | 2 |
# port setting |
3 | 3 |
server: |
4 | 4 |
port: 9080 |
5 |
+ servlet: |
|
6 |
+ session: |
|
7 |
+ cookie: |
|
8 |
+ name: JSESSIONID |
|
9 |
+ |
|
10 |
+# front url |
|
11 |
+frontUrl: http://localhost:80 |
|
5 | 12 |
|
6 | 13 |
# spring docs setting |
7 | 14 |
springdoc: |
... | ... | @@ -19,18 +26,29 @@ |
19 | 26 |
application: |
20 | 27 |
name: sj_wmp |
21 | 28 |
# Datasource configuration - postgresql |
29 |
+ datasource: |
|
30 |
+ driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy |
|
31 |
+ username: takensoft |
|
32 |
+ password: tts96314728!@ |
|
33 |
+ url: jdbc:log4jdbc:postgresql://210.180.118.83:5432/ai_lms?currentSchema=ai_lms |
|
34 |
+ # datasource: |
|
35 |
+# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy |
|
36 |
+# username: postgres |
|
37 |
+# password: 1234 |
|
38 |
+# url: jdbc:log4jdbc:postgresql://localhost/postgres?currentSchema=public |
|
39 |
+ |
|
40 |
+ # Datasource configuration - mariaDB |
|
22 | 41 |
# datasource: |
23 | 42 |
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy |
24 | 43 |
# username: root |
25 | 44 |
# password: 1234 |
26 |
-# url: jdbc:log4jdbc:postgresql://localhost/test?currentSchema=public |
|
27 |
- |
|
28 |
- # Datasource configuration - mariaDB |
|
29 |
- datasource: |
|
30 |
- driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy |
|
31 |
- username: root |
|
32 |
- password: 1234 |
|
33 |
- url: jdbc:log4jdbc:mariadb://localhost/test |
|
45 |
+# url: jdbc:log4jdbc:mariadb://localhost/test |
|
46 |
+ jwt: |
|
47 |
+ secret: 42b08045ac84dbcdf50e946bf8ad34d35af707979b3230cfb84fb8fe34236d2f |
|
48 |
+ accessTime: 600000 # 10분 600000 |
|
49 |
+ refreshTime: 86400000 # 24시간 86400000 |
|
50 |
+cookie: |
|
51 |
+ time: 86400 |
|
34 | 52 |
|
35 | 53 |
mybatis: |
36 | 54 |
type-aliases-package: com.takensoft.**.**.vo, com.takensoft.**.**.dto, com.takensoft.common |
+++ src/main/resources/mybatis/mapper/auth/auth-SQL.xml
... | ... | @@ -0,0 +1,96 @@ |
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
3 | +<mapper namespace="com.takensoft.sj_wmp.wmp.auth.dao.AuthDAO"> | |
4 | + | |
5 | + <resultMap id="userMap" type="UserVO"> | |
6 | + <result property="usid" column="usid"/> | |
7 | + <result property="loginId" column="login_id"/> | |
8 | + <result property="password" column="password"/> | |
9 | + <result property="userNm" column="user_nm"/> | |
10 | + <result property="email" column="email"/> | |
11 | + <result property="telno" column="telno"/> | |
12 | + <result property="useAt" column="use_at"/> | |
13 | + <result property="reg" column="reg"/> | |
14 | + <result property="registDt" column="regist_dt"/> | |
15 | + <result property="updusr" column="updusr"/> | |
16 | + <result property="updtDt" column="updt_dt"/> | |
17 | + <collection property="author" javaType="java.util.ArrayList" ofType="UserAuthorVO" select="findByUserAuthor" column="usid" /> | |
18 | + </resultMap> | |
19 | + | |
20 | + <resultMap id="authMap" type="UserAuthorVO"> | |
21 | + <result property="authorCode" column="author_code" /> | |
22 | + </resultMap> | |
23 | + <!-- | |
24 | + 작성자 : 방선주 | |
25 | + 작성일 : 2024.07.12 | |
26 | + 내 용 : 로그인 시 계정 검색 | |
27 | + --> | |
28 | + <select id="findByUserIdSecurity" parameterType="String" resultMap="userMap"> | |
29 | + SELECT usid | |
30 | + , login_id | |
31 | + , "password" | |
32 | + , user_nm | |
33 | ||
34 | + , telno | |
35 | + , use_at | |
36 | + , reg | |
37 | + , regist_dt | |
38 | + , updusr | |
39 | + , updt_dt | |
40 | + FROM users | |
41 | + WHERE login_id = #{loginId} | |
42 | + AND use_at = 'Y' | |
43 | + </select> | |
44 | + <!-- | |
45 | + 작성자 : 방선주 | |
46 | + 작성일 : 2024.07.12 | |
47 | + 내 용 : 로그인 시 계정 권한 검색 | |
48 | + --> | |
49 | + <select id="findByUserAuthor" parameterType="String" resultMap="authMap"> | |
50 | + SELECT author_code | |
51 | + FROM users_author | |
52 | + WHERE usid = #{usid} | |
53 | + </select> | |
54 | + <!-- | |
55 | + 작성자 : 방선주 | |
56 | + 작성일 : 2024.07.12 | |
57 | + 내 용 : 사용자 등록 관련 | |
58 | + --> | |
59 | + <insert id="insertUser" parameterType="AuthVO"> | |
60 | + INSERT INTO users( usid | |
61 | + , login_id | |
62 | + , "password" | |
63 | + , user_nm | |
64 | ||
65 | + , telno | |
66 | + , use_at | |
67 | + , reg | |
68 | + , regist_dt | |
69 | + )VALUES( #{usid} | |
70 | + , #{loginId} | |
71 | + , #{password} | |
72 | + , #{userNm} | |
73 | + , #{email} | |
74 | + , #{telno} | |
75 | + , 'Y' | |
76 | + , #{reg} | |
77 | + , now() | |
78 | + ); | |
79 | + </insert> | |
80 | + <!-- | |
81 | + 작성자 : 방선주 | |
82 | + 작성일 : 2024.07.18 | |
83 | + 내 용 : 사용자 권한 등록 | |
84 | + --> | |
85 | + <insert id="insertAuth" parameterType="HashMap"> | |
86 | + INSERT INTO users_author( | |
87 | + usid | |
88 | + , author_code | |
89 | + ) VALUES ( | |
90 | + #{usid} | |
91 | + , #{author_code} | |
92 | + ); | |
93 | + </insert> | |
94 | + | |
95 | + | |
96 | +</mapper>(파일 끝에 줄바꿈 문자 없음) |
+++ src/main/resources/mybatis/mapper/common/idgen-SQL.xml
... | ... | @@ -0,0 +1,32 @@ |
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
3 | +<mapper namespace="com.takensoft.sj_wmp.common.idgen.dao.IdgenMapper"> | |
4 | + <!-- | |
5 | + 작 성 자 : takensoft | |
6 | + 작 성 일 : 2024.01.01 | |
7 | + 내 용 : 테이블명으로 시퀀스 조회 | |
8 | + --> | |
9 | + <select id="selectNextId" parameterType="String" resultType="IdgenVO"> | |
10 | + SELECT aftr_id | |
11 | + FROM cmmn_idgn | |
12 | + WHERE tbl_nm = #{tblNm} | |
13 | + </select> | |
14 | + | |
15 | + <!-- | |
16 | + 작 성 자 : takensoft | |
17 | + 작 성 일 : 2024.04.01 | |
18 | + 내 용 : 시퀀스 등록 및 수정 | |
19 | + --> | |
20 | + <insert id="upsertSeqNmg" parameterType="IdgenVO"> | |
21 | + INSERT INTO cmmn_idgn ( | |
22 | + tbl_nm | |
23 | + , aftr_id | |
24 | + ) VALUES ( | |
25 | + #{tblNm} | |
26 | + , #{aftrId} | |
27 | + ) | |
28 | + ON CONFLICT (tbl_nm) | |
29 | + DO UPDATE | |
30 | + SET aftr_id = #{aftrId} | |
31 | + </insert> | |
32 | +</mapper>(파일 끝에 줄바꿈 문자 없음) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?