안녕하세요 영상강의를 보며 클론 코딩하면서 하나씩 배우고 있는데 백단에서 Cors 설정을 해주었음에도 불구하고 (강의 섹션 3 수정/삭제 처리 진행 중 ) @Override public void addCorsMappings ( CorsRegistry registry) { registry.addMapping( "/**" ) .allowedOrigins( "*" ) .allowedMethods( "HEAD" , "GET" , "POST" , "PUT" , "DELETE" , "OPTIONS" ) .maxAge( 300 ) .allowedHeaders( "Authorization" , "Cache-Control" , "Content-Type" ); } 여전히 호출 불가 상태로 있는데 원인을 모르겠습니다. 혹시나 몰라 todoApi.js 파일을 제공된 소스파일로 엎어쳐서 진행을 했는데도 불구하고 말이죠..
@ElementCollection와 @EntityGraph사용법에 대해서 잘 숙지 하였습니다. 한가지 질문이 있습니다. JPA사용시 일반적으로 쓰이는 @OneToMany, @ManyToOne, @ManyToMany를 대신해서 @ElementCollection으로대체하여 사용이 가능할까요? 왠지 될거같은생각이 들긴하는데....
아래와 같은 에러가 발생하여 application.properties 를 application.yml로 바꾸어봤지만 같은에러가납니다. *************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active). 아래 코드는 application.yml내용입니다. spring: datasource: driver-class-name: org.mariadb.jdbc.Driver url: jdbc:mariadb://localhost:3306/apidb username: apidbuser password: apidbuser jpa: hibernate: ddl-auto: update properties: hibernate: format_sql: true show-sql: true logging: level:debug 아래코드는 build.gradle 내용입니다. buildscript { ext { queryDslVersion = "5.0.0" } } plugins { id 'java' id 'org.springframework.boot' version '3.0.13' id 'io.spring.dependency-management' version '1.1.4' } group = 'org.mail' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' testCompileOnly'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' annotationProcessor 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" annotationProcessor( "jakarta.persistence:jakarta.persistence-api", "jakarta.annotation:jakarta.annotation-api", "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta") } tasks.named('bootBuildImage') { builder = 'paketobuildpacks/builder-jammy-base:latest' } tasks.named('test') { useJUnitPlatform() } compileJava.dependsOn('clean') 맨위에 에러 난 후 이하 반복적인 에러가 발생하지만 값을 가져오는데는 이상이없습니다. 프론트에서 호출해도 정상적으로 데이터가 호출됩니다. 그래서 quertdsl에 관한내용을 지우고 해봤는데 에러가 사라졌습니다. 혹시 querydsl 에 관한 이슈가 있는걸까요? 검색을 해봤지만 발견할 수가 없었습니다. java.lang.NullPointerException: Cannot read field "generatedClass" because "data" is null
강의에 나온대로 require()로 따라하던 중 import가 더 최신방식이라는 이야기를 듣게 되었습니다. 구글링을 해보니 require()를 쓰는 쪽은 CommonJS(CJS)이고 import 쓰는 쪽이 ESM이라는 걸 알게되었습니다 Es6(2015)부터 import를 쓸 수 있던거 같은데 그 이후에 나온 강의가 require를 쓰게된 이유가 있을까요? 사용되는 패키지의 호환성 이슈인지 다른 이유인지 궁금합니다
안녕하세요 연구실에서 자체적으로 실험기기와 컴퓨터랑 통신을 진행하는 중인데, 하나가 해결이 안 되어서 너무 답답해서 고수님들께 자문을 구하려고 합니다. Rs232 rtu 모드를 지원한다고 한 OS-20 overhead stirrer과 통신을 진행 중 입니다. 이 친구의 통신 규격과 방식은 아래 그림 3개와 같습니다. 이중 stirrer control 부분을 제가 참조해서 저 command를 hex 방식으로 입력하였는데 도무지 안되는 겁니다. 그런데 웃긴게 이 회사에서 지원하는 공식 통신프로그램을 사용하면 작동이 잘 되더군요. Instruction overview에서 나온 규칙은 다음과 같습니다. Command 구조는 Prefix Instruction_code Data_frame Checksum로 되어 있고 입력의 prefix는 0xfe로 시작하며 responce는 0xfd로 시작합니다. 모든 바이트 사이에는 50ms delay가 존재해야하며 Dataframe은 큰 수 자리부터 전송합니다. ex) 1000rpm을 data frame에 입력하려고 할 시 Hex값이 03E8이니까 앞에 두 자리를 0x03에 해당하고 뒤에 두 자리를 0xE8로 해당시킵니다. Null은 0x00입니다. Checksum 방식은 0xfe,0xfd인 prefix를 제외하고 나머지를 전부 더한 값으로 0xnn 이런식으로 표현됩니다. 신기하게도 16진수의 2자리를 넘어가도 뒤에 2 자리만 붙이면 된다고 하더군요. ex) 0xfe 0xb1 0x03 0xe8 0x00 checksum인데 0xfe를 제외하고 다 더하면 019c이지만 0x9c만 입력하면 되는 형식입니다. 그래서 이 규칙대로 코드를 짜서 통신을 해 보았는데, 아무리 해도 안되어서 너무 답답합니다. 심지어 제가 잘못했는지 확인하려고 시리얼 통신 sniffer을 사용하여서 공식 프로그램에서는 어떻게 통신이 되나 뜯어보았습니다. 결과는 아래 사진과 같습니다. 제가 python으로 작성한 코드는 아래와 같습니다. import serial import time ser = serial.Serial( port='COM7', # Update with your actual port baudrate=9600, parity=serial.PARITY_NONE, # No parity stopbits=serial.STOPBITS_ONE, # 1 stop bit bytesize=serial.EIGHTBITS # 8 data bits ) def send_hex_string(hex_string): # Convert the hex string to bytes byte_data = bytes.fromhex(hex_string) # Send the bytes over the serial port ser.write(byte_data) def send_hex_string_with_delay(hex_string, delay_ms=50): for i in range(0, len(hex_string), 2): # Extract each pair of characters and convert to bytes hex_pair = hex_string[i:i + 2] byte_data = bytes.fromhex(hex_pair) # Send the bytes over the serial port ser.write(byte_data) # Wait for the specified delay time.sleep(delay_ms / 1000.0) command = 'feb103e8009c' send_hex_string_with_delay(command) ser.close() 또한 파이썬에서의 결과를 시리얼 전송으로 보면 다음과 같습니다. 입력은 제대로 되는데 기기에는 반응이 제대로 나오지 않네요... 제가 잘못하고 빠뜨린 점이 있을까요? 읽어주셔서 정말 감사드립니다.
안녕하세요 늘 좋은 강의 올려주셔서 감사합니다. authenticationManager 파라미터 전달 부분에서 문제가 있어 이렇게 게시글 남깁니다! 새로 올려주신 소스코드를 보며 새로 업데이트된 시큐리티에서 사용하기위해 authenticationManager 를 파라미터로 전달하는 부분을 적용하였습니다 그런데 Authentication authentication = authenticationManager.authenticate(authenticationToken); 부분에서 loadbyUsername() 함수를 호출하지 못하고 있습니다... JwtAuthenticationFilter // 유저네임 패스워드 토큰 생성 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loginUser.getUsername(), loginUser.getPassword() ); System.out.println("JwtAuthenticationToken : 토큰생성완료"); // authenticate() 함수가 호출 되면 인증 프로바이더가 유저 디테일 서비스의 // loadUserByUsername(토큰의 첫번째 파라메터) 를 호출하고 // UserDetails를 리턴받아서 토큰의 두번째 파라메터(credential)과 // UserDetails(DB값)의 getPassword()함수로 비교해서 동일하면 // Authentication 객체를 만들어서 필터체인으로 리턴해준다. // Tip: 인증 프로바이더의 디폴트 서비스는 UserDetailsService 타입 // Tip: 인증 프로바이더의 디폴트 암호화 방식은 BCryptPasswordEncoder // 결론은 인증 프로바이더에게 알려줄 필요가 없음. Authentication authentication = authenticationManager.authenticate(authenticationToken); System.out.println("authentication : authentication 생성 완료"); PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal(); System.out.println("Authentication : " + principalDetails.getUser().getUsername()); return authentication; SecurityConfig @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final CosConfig cosConfig; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); http.csrf(csrf -> csrf.disable()); http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); http.addFilter(cosConfig.corsFilter()); // cors 허용 설정 http.addFilterBefore(new MyFilter3(), SecurityContextPersistenceFilter.class); http.formLogin(login -> login.disable()); http.httpBasic(basic -> basic.disable()); http.addFilter(new JwtAuthenticationFilter(authenticationManager)); http.authorizeHttpRequests(request -> request.requestMatchers("/api/v1/user/**") .hasAnyRole("USER", "MANAGER", "ADMIN") .requestMatchers("/api/v1/manager/**") .hasAnyRole("MANAGER", "ADMIN") .requestMatchers("/api/v1/admin/**") .hasRole("ADMIN") .anyRequest().permitAll() ); return http.getOrBuild(); } 와 같이 SecurityConfig를 업데이트된 Spring Security 독스를 보고 선생님께서 강의해주신 내용대로 만들어보았습니다. 터미널에서는 JwtAuthentication Filter : 로그인 시도중 JwtAuthenticationFilter : UserEntity(id=0, email=null, password=qwer1234, username=ssar, role=null, createDate=null) JwtAuthenticationToken : 토큰생성완료 와 같이 JwtAuthenticationToken : 토큰생성완료 까지는 정상적으로 되는걸 확인하였습니다. 이후 loadByUsername() 부분에 따로 출력을 찍어 확인한결과 호출이 안되는걸 확인했습니다. @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserEntity userEntity = this.userDao.findByUsername(username); System.out.println("================ loadUserByUsername ================"); System.out.println(userEntity); System.out.println("---------------- loadUserByUsername -----------------"); return new PrincipalDetails(userEntity); } 어떤 부분이 잘못되어서 그런건지 찾지 못하여 게시글 남깁니다! 늘 좋은강의 감사합니다! 개인적으로 문제점이 된다고 생각한 부분 AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); 에서 authenticationManager를 받는 부분이 제대로 안되는것 같습니다... 추가로 SecurityConfig 에서 authenticationManager 부분을 로그로 찍어본 결과 null 출력되는걸 확인했습니다... authenticationManager부분이 생성이 안되는걸까요?
@Configuration public class BCryptConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 위와 같이 Config class에 PasswordEncoder 빈을 생성했는데도 Description: Parameter 1 of constructor in domain.Member.service.MemberService required a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' that could not be found. Action: Consider defining a bean of type 'org.springframework.security.crypto.password.PasswordEncoder' in your configuration. Process finished with exit code 1 와 같이 에러가 발생하면 어떻게 해야할까요?
당연히 웹앱이 API에 요청을 할때도 올바른 대상이 요청하는게 맞는지 별도의 검증이 필요하지만 우선 그건 무시하고 순수히 웹앱의 유저 인증만 생각했을때의 이야기입니다.. 프론트 역할을 하는 html, css, (바닐라js or jQuery) + spring boot(thymeleaf, spring security) 웹어플리케이션 프로젝트가 있고 회원이 있는지 조회할 수 있는 API 서버(DB와 연결된 spring boot)가 별도로 존재했을때 어떤 프로젝트에 어떤 식으로 시큐리티 및 토큰생성 세팅을 해야할지 감이 잘 오지 않습니다.. 제가 구현하고자 하는건 회원/비회원에 따라 페이지를 동적으로 바꾸거나 (로그인이 로그아웃으로 바뀐다든지) 페이지에 접근을 못하게 하려고 합니다 (마이페이지) 제 생각에는 구현내용 둘 다 API를 굳이 갈 필요가 없기 때문에 웹앱단에서 검증이 이루어져야 할 것 같은데 맞을까요..? API는 회원 유무를 조회한 뒤, 존재하는 경우 단순히 유저정보(or 아예 토큰을 만들어서 넘긴다..?)를 웹앱에 넘겨주는 것까지가 역할이고, 따라서 Spring Security는 여기서 필요하지 않다 웹앱 프로젝트에 스프링 시큐리티 설정을 한 뒤, 스프링부트단에서 API로부터 전달받은 토큰, 혹은 유저정보를 가지고 인증을 처리한다 (하지만 어떻게..?) 이런 흐름이 맞는지 모르겠습니다..