묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문
형 변환 생성자와 캐스팅
#include <iostream> using namespace std; class Knight { public: Knight() { cout << "[알림] 기본 생성자 호출" << endl; this->hp = 10; this->mp = 10; } Knight(int hp) { cout << "[알림] 타입 변환 생성자 호출" << endl; this->hp += hp; } ~Knight() { cout << "[알림] 소멸자 호출" << endl; } void print() { cout << "[정보] HP: " << this->hp << " MP: " << this->mp << endl; } public: int hp; int mp; }; int main() { // 1. 기본 자료형 형 변환 연산자 사용 // a의 값에 대해 형 변환 '연산자'를 사용하여 형 변환된 결과를 반환 후 b에 할당 int a = 3; double b = (double)a; // 2. 객체형에 대한 형 변환 생성자 사용 // (1) 기본적인 타입 변환 연산자 호출 순서 : 타입->소멸 Knight k1(5); k1.print(); // (2) 묵시적 타입 변환 연산자 호출 순서 : 타입->소멸 Knight k2 = 10; k2.print(); // (3) 기본 생성자로 생성 후 묵시적 타입 변환 연산자 호출하여 재할당 순서 : 기본->타입->소멸->소멸 Knight k3; k3 = 10; k3.print(); return 0; }[1]의 상황 - 이해하였습니다.해당하는 기본 자료형의 경우 단항 연산자인 "형 변환 연산자"에 의해 연산된 결과가 반환되어 double형 변수 b에 정상 할당되었습니다.[2-1]의 상황 - 이해하였습니다.오버로딩된 기본 연산자 중 인수가 하나인 타입 변환 생성자가 자동으로 호출되어 객체가 생성되었습니다.[질문 항목]Q1.[2-2] [2-3]의 상황 - 헷갈립니다.묵시적으로 형 변환 타입 생성자가 호출되어 우항의 Knight(10)이 우선 동작하고 그 결과가 반환되어 k2에 할당되었다라고 생각하였는데 실제 어셈블리로 동작을 확인하니 예상했던 순서로 동작하지 않고 바로 타입 변환 연산자가 호출되어 [2-1]과 [2-2]는 완전히 같았습니다. 기본 자료형에 대한 casting 처럼 캐스팅이 먼저 동작되고 그 결과가 반환되어 좌항에 할당된다고 생각했습니다. 그런데 반환형이 없는 생성자인데 대입 연산자 기준 우측에서 사용될 수 있었던건 의미만 캐스팅일 뿐, 실제로는 형 변환 연산자의 호출의 다른 방법이기 때문인가요? (실제로는 타입 변환이 아닌 인수가 1개인 기본 생성자 호출인데 사용 방법이 마치 형 변환과 같아서 이름이 그렇게 붙은건가요?)복잡하게 생각하지 않는다면,타입 변환 생성자는 1) 그 자체로 생성자로 활용 2) 캐스팅의 두 가지 사용처가 있고 1), 2) 모두 내부적으로 같은 방식으로 동작함.이라고 이해해도 괜찮을까요? 바로 전에 작성한 질문은 생각을 제대로 정리하지 못해 글이 난해하여 다시 정리하여 올리게 되었습니다.좋은 강의 감사드립니다.정말 많이 배우고있고 큰 도움이 되고 있습니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
members 500 오류
제가 다 실험을 해봤는데 아래 문구때매 자꾸 서버가 500이 뜹니다. 강의 내용에 맞게 복붙해서 붙였는데 왜 자꾸 뜨는지 모르겠습니다...... 처음의 저 문제의 코드가 오류가 떠서 구글링 한결과 gradle에 아래를 추가했습니다. 오류가 안떠서 코드를 돌렸더니 서버가 500이 뜹니다... 도와주세요 ㅜㅜㅜimplementation group: 'javax.servlet', name: 'jstl', version: '1.2'gradle에 위와같은 문구를 추가했습니다. <%@ page contentType="text/html;charset=UTF-8" language="java" %>문제의 코드<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="/index.html">메인</a> <table> <thead> <th>id</th> <th>username</th> <th>age</th> </thead> <tbody> <c:forEach var="item" items="${members}"> <tr> <td>item.id</td> <td>item.username</td> <td>item.age</td> </c:forEach> </tbody> </table> </body> </html> 전체 members.jsp 코드 package hello.servlet.web.servletmvc; import hello.servlet.domain.member.Member; import hello.servlet.domain.member.MemberRepository; import jakarta.servlet.RequestDispatcher; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @WebServlet(name="mvcMemberListServlet", urlPatterns = "/servlet-mvc/members") public class MvcMemberListServlet extends HttpServlet { MemberRepository memberRepository=MemberRepository.getInstance(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Member> members = memberRepository.findAll(); request.setAttribute("members",members); String viewPath="/WEB-INF/views/members.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request,response); } } MvcMemberListServlet 코드
-
해결됨
oauth2 로그인 시 권한 저장
프로젝트에서 점주, 회원을 구분해서 로그인을 구현했습니다.점주로 회원가입 시 /api/owners 로 request가 오고회원으로 회원가입 시 /api/members로 request가 옵니다.그래서 createRoles를 밑에 사진처럼 구현을 했습니다.그런데 OAuth2로 로그인을 하면 requestURI가 /login/oauth2/code 이걸로 와서 권한이 MEMBER로만 저장이 됩니다.owner와 member 구분을 어떻게 할 수 있을까요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
sequlize같은 orm에 대한 질문
javascript는 sequilize java는 JPA같은 데이터베이스를 다루는 ORM이 있는 것 같은데 ORM에 대해 좀더 찾아보니 sql 쿼리문을 직접 작성하는 것보다 코드의 양도 줄고 유지 보수도 더 쉬운 것 같습니다.나중에 sql 쿼리문을 직접 입력하는 방식을 배워야하나 생각이 들었지만 이렇게 장점이 많은 ORM을 안 쓸 이유가 없는 것 같고 나중에 다른 백앤드 프레임 워크 예를 들어 java Spring같은 것을 배워도 JPA같은 ORM을 배우지 sql 쿼리문을 직접 넣는 방식으로는 하지 않을꺼 같습니다.그럼에도 불구하고 sql 쿼리문을 직접 넣는 방식을 배워둘 필요가 있을까요? 아니면 ORM방식에 단점이 있을까요?
-
미해결Vue.js 중급 강좌 - 웹앱 제작으로 배워보는 Vue.js, ES6, Vuex
깃허브 권한 요청드립니다.
인프런 아이디 : kgi70인프런 이메일 : kgi70@naver.com깃헙 아이디 : kgi70@naver.com깃헙 Username : gikim07
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
@ModelAttribute 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용] //@PostMapping("/add") //requestParam 은 form 의 name 이름과 같아야함 public String saveV3(@ModelAttribute Item item,Model model){ // @ModelAttribute("item") 도생략가능하다. //Item (class명) ->item itemRepository.save(item); return "/basic/item"; }이 코드에서 @ModelAttribute 가 html 의 name 속성과 Item class 를 매칭시켜주고그래서 itemRepository에 저장 로직에서 사용된다는 거까지는 이해했습니다. 그러나 다시 '/basic/item' 화면으로 갈때 어떻게 저장시킨 item 이 화면에 렌더링되는건지 궁금합니다. Item newItem = itemRepository.save(item); model.addAttribute("item",newItem); 즉 , 이 과정이 어떻게 생략되서 작동되는지 원리가 궁금합니다.
-
미해결[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
padding 같은 단위에 꼭 소수점을 붙이는 이유
EdgeInsets.symmetric( horizontal: 16.0) 처럼16으로 줘도 double로 인식하는 것 같던데 꼭 소수점을 적어야 하는 이유가 있나요??
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
7강 질문있습니다
7강에서 PostMapping과 GetMapping에 URL로 /user을 입력했는데 홈페이지에서 사용자 등록버튼을 누르거나 목록창을 눌러도 url은 전혀 변하지 않습니다. url로 클라이언트가 요청을해서 서버가 응답하는 거라고 알고있는데 어떻게 이렇게 작용하는건가요?url이 바뀌지 않아도 요청을 받아들이는건가요?
-
미해결[코드팩토리] [초급] 8시간만에 끝내는 코드팩토리의 Typescript 완전정복 풀코스
code runner- output이 깨져요
위와 같이 아웃풋이 깨집니다.js에서 사용할 때는 깨지지 않았는데, 어떻게 해결해야 할지 여쭙습니다 ㅠ
-
미해결한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
onClick 사용시 질문입니다!
onClick를 이용할경우 onClick= { ( ) => ?? } 해당 형식으로 사용해야하는 경우가 있고 아닌경우가 있는데 헷갈리네요 ㅜㅜ 클릭할떄 실행되는함수가 파라미터를 받지않는다면 onClick={함수명} 이런식이고 파라미터를 받는다면 onClick={( )=>함수명( 파라미터 )} 이런식인거같은데 다른경우도 있을까요?? 콜백 함수에 관한 영상을 찾아보면 이해가 될까요??
-
해결됨JSP 웹 쇼핑몰 프로그래밍 기본 과정(JSP WEB Programming)
toad 를 사용할수가 없는데 sql developer 를 사용하여 수업참여 가능한가요?
toad 를 사용할수가 없는데 sql developer 를 사용하여 수업참여 가능한가요?
-
해결됨생활코딩 - 자바스크립트(JavaScript) 기본
제발 도와주세요
javascript로 프로젝트 하는 학생입니다.제가 지금 로그인 창으로 적은 아이디,비번,이메일을 적은 값을 저장해다른 html창으로 보내는 것을 하고 싶은 데 잘 안되고 있습니다.(방문자 로그를 만들기 위해)도움이 필요 합니다..<방문자 로그를 표시할 창>->ex) jjj.html<로그인 창 코드><html> <div style="text-align: center;"> <img src="file:///C:/Users/User/Pictures/image%20(2).png" height="300" width="300"> </div> <title>mago market</title> <body> <style>p{text-align: center;}</style> </body> <script> const input = document.querySelector("input"); let text = input.innertext; localstorage.setItem("text", text); </script> <form action="file:///C:/Users/User/jjj.html" method="post" class="input form"> <p style="color:rgb(202, 202, 202) ">아이디는 첫 글자를 영어를 포함해 주세요</p> <p>아이디: <input type="text" id="id" required pattern="[a-zA-Z].+" placeholder="아이디를 작성해 주세요" class="input id"></p> <p>비밀번호: <input type="password" id="pwd" required placeholder="비밀번호를 작성해 주세요" class="input pw"></p><p>이메일: <input type="email" id="email" placeholder="이메일을 작성해 주세요" required></p> <p>gps 및 위치 정보를 공유하는 것을 동의합니까? <input type="checkbox" name="agree" required></p> <p>계정 정보를 수집하는 것을 동의합니까? <input type="checkbox" name="yes" required></p> <div style="text-align: center;"> <input type="submit" type="button" value="로그인"> </div> <script type="text/javascript"> alert("이곳은 GSM 학생들이 사용할 Mago Market 사이트 페이지 입니다.\n참고하시길 바랍니다.\n제작자 진건희"); </script> </form>
-
미해결스프링부트 시큐리티 & JWT 강의
[급함]로그인시 jwt 발급 문제
https://github.com/YuYoHan/project_study1 전체 코드 질문 1) // 로그인 @PostMapping("/api/v1/users/login") public ResponseEntity<?> login(@RequestBody MemberDTO memberDTO) throws Exception { log.info("member : " + memberDTO); try { log.info("-----------------"); ResponseEntity<TokenDTO> login = memberService.login(memberDTO.getUserEmail(), memberDTO.getUserPw()); log.info("login : " + login); return ResponseEntity.ok().body(login); } catch (Exception e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("문제가 있습니다"); } } // 로그인 public ResponseEntity<TokenDTO> login(String userEmail, String userPw) throws Exception { // Login ID/PW를 기반으로 UsernamePasswordAuthenticationToken 생성 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userEmail, userPw); log.info("----------------------"); log.info("authenticationToken : " +authenticationToken); log.info("----------------------"); // 실제 검증(사용자 비밀번호 체크)이 이루어지는 부분 // authenticateToken을 이용해서 Authentication 객체를 생성하고 // authentication 메서드가 실행될 때 // CustomUserDetailsService에서 만든 loadUserbyUsername 메서드가 실행 Authentication authentication = authenticationManagerBuilder .getObject().authenticate(authenticationToken); log.info("----------------------"); log.info("authentication : " + authentication); log.info("----------------------"); // 해당 객체를 SecurityContextHolder에 저장 SecurityContextHolder.getContext().setAuthentication(authentication); // authentication 객체를 createToken 메소드를 통해서 생성 // 인증 정보를 기반으로 생성 TokenDTO tokenDTO = jwtProvider.createToken(authentication); log.info("----------------------"); log.info("tokenDTO : " + tokenDTO); log.info("----------------------"); HttpHeaders headers = new HttpHeaders(); // response header에 jwt token을 넣어줌 headers.add(JwtAuthenticationFilter.HEADER_AUTHORIZATION, "Bearer " + tokenDTO); log.info("----------------------"); log.info("headers : " + headers); log.info("----------------------"); MemberEntity member = memberRepository.findByUserEmail(userEmail); log.info("member : " + member); TokenEntity tokenEntity = TokenEntity.builder() .grantType(tokenDTO.getGrantType()) .accessToken(tokenDTO.getAccessToken()) .refreshToken(tokenDTO.getRefreshToken()) .userEmail(tokenDTO.getUserEmail()) .nickName(member.getNickName()) .userId(member.getUserId()) .build(); log.info("token : " + tokenEntity); tokenRepository.save(tokenEntity); return new ResponseEntity<>(tokenDTO, headers, HttpStatus.OK); }package com.example.project1.config.auth; import com.example.project1.entity.member.MemberEntity; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import java.util.ArrayList; import java.util.Collection; import java.util.Map; @Setter @Getter @ToString public class PrincipalDetails implements UserDetails, OAuth2User { private MemberEntity member; private Map<String, Object> attributes; // 일반 로그인 public PrincipalDetails(MemberEntity member) { this.member = member; } // OAuth2 로그인 public PrincipalDetails(MemberEntity member, Map<String, Object> attributes) { this.member = member; this.attributes = attributes; } // 해당 유저의 권한을 리턴하는 곳 @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> collection = new ArrayList<>(); collection.add(new GrantedAuthority() { @Override public String getAuthority() { return "ROLE_" + member.getUserType().toString(); } }); return collection; } // 사용자 패스워드를 반환 @Override public String getPassword() { return member.getUserPw(); } // 사용자 이름 반환 @Override public String getUsername() { return member.getUserEmail(); } // 계정 만료 여부 반환 @Override public boolean isAccountNonExpired() { // 만료되었는지 확인하는 로직 // true = 만료되지 않음 return true; } // 계정 잠금 여부 반환 @Override public boolean isAccountNonLocked() { // true = 잠금되지 않음 return true; } // 패스워드의 만료 여부 반환 @Override public boolean isCredentialsNonExpired() { // 패스워드가 만료되었는지 확인하는 로직 // true = 만료되지 않음 return true; } // 계정 사용 가능 여부 반환 @Override public boolean isEnabled() { // 계정이 사용 가능한지 확인하는 로직 // true = 사용 가능 return true; } @Override public Map<String, Object> getAttributes() { return attributes; } @Override public String getName() { return null; } }@Service @RequiredArgsConstructor @Slf4j public class PrincipalDetailsService implements UserDetailsService { private MemberRepository memberRepository; // 시큐리티 session = Authentication = UserDetails // 함수 종료시 @AuthenticationPrincipal 어노테이션이 만들어진다. @Override public UserDetails loadUserByUsername(String userEmail) throws UsernameNotFoundException { MemberEntity member = memberRepository.findByUserEmail(userEmail); log.info("user : " + member); return new PrincipalDetails(member); } }package com.example.project1.config.jwt; import com.example.project1.domain.jwt.TokenDTO; import io.jsonwebtoken.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Component; import io.jsonwebtoken.security.Keys; import javax.xml.bind.DatatypeConverter; import java.security.Key; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.stream.Collectors; @Slf4j @Component public class JwtProvider { private static final String AUTHORITIES_KEY = "auth"; @Value("${jwt.access.expiration}") private long accessTokenTime; @Value("${jwt.refresh.expiration}") private long refreshTokenTime; private Key key; public JwtProvider( @Value("${jwt.secret_key}") String secret_key) { byte[] secretByteKey = DatatypeConverter.parseBase64Binary(secret_key); this.key = Keys.hmacShaKeyFor(secretByteKey); } // 유저 정보를 가지고 AccessToken, RefreshToken 을 생성하는 메소드 public TokenDTO createToken(Authentication authentication) { // 권한 가져오기 String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); long now = (new Date()).getTime(); Date now2 = new Date(); // AccessToken 생성 Date accessTokenExpire = new Date(now + this.accessTokenTime); String accessToken = Jwts.builder() // 내용 sub : 유저의 이메일 // 토큰 제목 .setSubject(authentication.getName()) // 클레임 id : 유저 ID .claim(AUTHORITIES_KEY, authorities) // 내용 exp : 토큰 만료 시간, 시간은 NumericDate 형식(예: 1480849143370)으로 하며 // 항상 현재 시간 이후로 설정합니다. .setExpiration(accessTokenExpire) // 서명 : 비밀값과 함께 해시값을 ES256 방식으로 암호화 .signWith(key, SignatureAlgorithm.HS256) .compact(); log.info("accessToken : " + accessToken); // RefreshToken 생성 Date refreshTokenExpire = new Date(now + this.refreshTokenTime); String refreshToken = Jwts.builder() .setSubject(authentication.getName()) .claim(AUTHORITIES_KEY, authorities) .setExpiration(refreshTokenExpire) .signWith(key, SignatureAlgorithm.HS256) .compact(); log.info("refreshToken : " + refreshToken); return TokenDTO.builder() .grantType("Bearer") .accessToken(accessToken) .refreshToken(refreshToken) // principalDeatails에서 getUserName 메소드가 반환한 것을 담아준다. // 이메일을 반환하도록 구성했으니 이메일이 반환됩니다. .userEmail(authentication.getName()) .build(); } // accessToken 생성 public TokenDTO createAccessToken(String userEmail) { Long now = (new Date()).getTime(); Date now2 = new Date(); Date accessTokenExpire = new Date(now + this.accessTokenTime); String accessToken = Jwts.builder() .setIssuedAt(now2) .setSubject(userEmail) .setExpiration(accessTokenExpire) .signWith(key, SignatureAlgorithm.HS256) .compact(); log.info("accessToken : " + accessToken); return TokenDTO.builder() .grantType("Bearer ") .accessToken(accessToken) .userEmail(userEmail) .build(); } // JWT 토큰을 복호화하여 토큰에 들어있는 정보를 꺼내는 코드 // 토큰으로 클레임을 만들고 이를 이용해 유저 객체를 만들어서 최종적으로 authentication 객체를 리턴 // 인증 정보 조회 public Authentication getAuthentication(String token) { // 토큰 복호화 메소드 Claims claims = parseClaims(token); if(claims.get("auth") == null) { throw new RuntimeException("권한 정보가 없는 토큰입니다."); } // 클레임 권한 정보 가져오기 Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); // UserDetails 객체를 만들어서 Authentication 리턴 User principal = new User(claims.getSubject(), "", authorities); return new UsernamePasswordAuthenticationToken(principal, token, authorities); } private Claims parseClaims(String token) { try { return Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); } catch (ExpiredJwtException e) { log.info("ExpiredJwtException : " + e.getMessage()); log.info("ExpiredJwtException : " + e.getClaims()); return e.getClaims(); } } // 토큰의 유효성 검증을 수행 public boolean validateToken(String token) { try { Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token); return true; } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { log.info("잘못된 JWT 서명입니다."); } catch (ExpiredJwtException e) { log.info("만료된 JWT 토큰입니다."); } catch (UnsupportedJwtException e) { log.info("지원되지 않는 JWT 토큰입니다."); }catch (IllegalArgumentException e) { log.info("JWT 토큰이 잘못되었습니다."); } return false; } }@RequiredArgsConstructor @Slf4j public class JwtAuthenticationFilter extends GenericFilterBean { public static final String HEADER_AUTHORIZATION = "Authorization"; private final JwtProvider jwtProvider; // doFilter는 토큰의 인증정보를 SecurityContext에 저장하는 역할 수행 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; // Request Header에서 JWT 토큰을 추출 String jwt = resolveToken(httpServletRequest); String requestURI = httpServletRequest.getRequestURI(); if(StringUtils.hasText(jwt) && jwtProvider.validateToken(jwt)){ // 토큰이 유효할 경우 토큰에서 Authentication 객체를 가지고 와서 SecurityContext에 저장 Authentication authentication = jwtProvider.getAuthentication(jwt); SecurityContextHolder.getContext().setAuthentication(authentication); log.info("Security Context에 '{}' 인증 정보를 저장했습니다., uri : {}", authentication.getName(), requestURI); } else { log.debug("유효한 JWT 토큰이 없습니다. uri : {}", requestURI); } chain.doFilter(request, response); } // Request Header 에서 토큰 정보를 꺼내오기 위한 메소드 private String resolveToken(HttpServletRequest httpServletRequest) { String bearerToken = httpServletRequest.getHeader(HEADER_AUTHORIZATION); if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } else { return null; } } }대략 적인 코드는 다음과 같습니다.근데 컨트롤러에서 로그인 시 Exception에 걸려서 문제가 있다고 문구 찍은게 나오네요. log 돌려보니까 service에서 authenticationToken객체는 나오는데 authentication 여기서 부터 안나오는거 보니 여기서 문제가 있는거 같은데 400번 bad Request가 뜹니다 ㅠㅠ 질문2) 현재 방법이 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userEmail, userPw);을 통해서 authentication으로 token을 생성하고 있는데 그냥 userEmail로만 받고 // accessToken 생성 public TokenDTO createAccessToken(String userEmail) { Long now = (new Date()).getTime(); Date now2 = new Date(); Date accessTokenExpire = new Date(now + this.accessTokenTime); String accessToken = Jwts.builder() .setIssuedAt(now2) .setSubject(userEmail) .setExpiration(accessTokenExpire) .signWith(key, SignatureAlgorithm.HS256) .compact(); log.info("accessToken : " + accessToken); return TokenDTO.builder() .grantType("Bearer ") .accessToken(accessToken) .userEmail(userEmail) .build(); }이런식으로 토큰을 생성해도 괜찮나요?질문3) JwtAuthenticationFilter 클래스에서 @RequiredArgsConstructor @Slf4j public class JwtAuthenticationFilter extends GenericFilterBean { public static final String HEADER_AUTHORIZATION = "Authorization"; private final JwtProvider jwtProvider; // doFilter는 토큰의 인증정보를 SecurityContext에 저장하는 역할 수행 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; // Request Header에서 JWT 토큰을 추출 String jwt = resolveToken(httpServletRequest); String requestURI = httpServletRequest.getRequestURI(); if(StringUtils.hasText(jwt) && jwtProvider.validateToken(jwt)){ // 토큰이 유효할 경우 토큰에서 Authentication 객체를 가지고 와서 SecurityContext에 저장 Authentication authentication = jwtProvider.getAuthentication(jwt); SecurityContextHolder.getContext().setAuthentication(authentication); log.info("Security Context에 '{}' 인증 정보를 저장했습니다., uri : {}", authentication.getName(), requestURI); } else { log.debug("유효한 JWT 토큰이 없습니다. uri : {}", requestURI); } chain.doFilter(request, response); } // Request Header 에서 토큰 정보를 꺼내오기 위한 메소드 private String resolveToken(HttpServletRequest httpServletRequest) { String bearerToken = httpServletRequest.getHeader(HEADER_AUTHORIZATION); if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } else { return null; } } }이 처리를 해줬으니 만약 access token이 만료되서 refresh token을 보내서 access token을 발급받으려고 할 때 Bearer가 있는지 확인을 더 해줄 필요 없이 여기서 처리하니 바로 header에 담겨온 refresh token을 빼와서 유효성 검사를 해주고 access token을 발급해주면 되나요?
-
미해결[리뉴얼] 타입스크립트 올인원 : Part2. 실전 분석편
declare namespace vs namespace
declare namespace JQuery { ... namespace Ajax { ... }}두가지 궁금한 부분이 있습니다.declare namespace를 쓰면 내부의 멤버들을 직접 export 하지 않아도 자동으로 모두 내보내지고 namespace만 쓸 경우엔 멤버들을 외부에 공개할려면 직접 export 해야하는걸로 아는데 이렇게 알고 있어도 될까요?위 코드도 JQuery가 declare로 선언되었으니 외부에서 Ajax 네임스페이스에 접근가능하니 declare를 선언하지 않은걸로 봐도 될까요? 아니면 다른 이유가 더 있는걸까요?
-
미해결
인프런 사업자등록증
재직중인 회사로부터 인프런 수강 학습비 지원을 지급받기 위해 인프런의 사업자등록증이 필요합니다.Info 이메일로 요청드렸는데 확인 부탁드립니다. 감사합니다.
-
미해결파이썬 알고리즘 문제풀이 입문(코딩테스트 대비)
채점 프로그램 질문
안녕하세요 ~ 강의 잘 듣고 있는 수강생입니다.강의용 채점 프로그램이 혹시 in out 외에 추가적인 테스트 케이스가 있는 걸까요?
-
미해결토비의 스프링 부트 - 이해와 원리
'DataSource 자동 구성 클래스' 강의 중 DataSourceConfig 클래스 설정
안녕하세요. 정말 재밌고 알찬 강의 잘 보고 있습니다. 영상에 추가가 안 된 부분인거 같아 질문 올립니다.DataSource 자동 구성 클래스 강의 중에 'DataSourceConfig' 클래스를 정의하고, com.southouse.config.MyAutoConfiguration.imports에 패키지 이름을 추가해줘야 하는데 이 부분이 영상에서 빠진거 같아서요.
-
미해결ChatGPT 영어 상황극 채팅 서비스 만들기 (Feat. 파이썬/장고채널스)
환경변수 로딩이 안됩니다 ㅠㅠ
안녕하세요 장고 환경변수 로딩하는 부분, 몇번 돌려보면서 확인했는데 계속 에러가 나오네요. 혹시 어떤게 잘못되었을지 알 수 있을까요.. 도와주세요..(venv) C:\Users\user\Documents\django_chat>python manage.py shellPython 3.10.9 | packaged by Anaconda, Inc. | (main, Mar 1 2023, 18:18:15) [MSC v.1916 64 bit (AMD64)] on win32Type "help", "copyright", "credits" or "license" for more information.(InteractiveConsole)>>> from django.conf import settings>>> settings.OPENAI_API_KEYTraceback (most recent call last): File "C:\Users\user\Documents\django_chat\venv\lib\site-packages\environ\environ.py", line 387, in get_value value = self.ENVIRON[var_name] File "C:\Users\user\anaconda3\lib\os.py", line 680, in getitem raise KeyError(key) from NoneKeyError: 'OPENAI_API_KEY'The above exception was the direct cause of the following exception:Traceback (most recent call last): File "<console>", line 1, in <module> File "C:\Users\user\Documents\django_chat\venv\lib\site-packages\django\conf\__init__.py", line 102, in getattr self._setup(name) File "C:\Users\user\Documents\django_chat\venv\lib\site-packages\django\conf\__init__.py", line 89, in _setup self._wrapped = Settings(settings_module) File "C:\Users\user\Documents\django_chat\venv\lib\site-packages\django\conf\__init__.py", line 217, in init mod = importlib.import_module(self.SETTINGS_MODULE) File "C:\Users\user\anaconda3\lib\importlib\__init__.py", line 126, in import_module return bootstrap.gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in gcdimport File "<frozen importlib._bootstrap>", line 1027, in findand_load File "<frozen importlib._bootstrap>", line 1006, in findand_load_unlocked File "<frozen importlib._bootstrap>", line 688, in loadunlocked File "<frozen importlib._bootstrap_external>", line 883, in exec_module File "<frozen importlib._bootstrap>", line 241, in callwith_frames_removed File "C:\Users\user\Documents\django_chat\mysite\settings.py", line 134, in <module> OPENAI_API_KEY=env.str("OPENAI_API_KEY") File "C:\Users\user\Documents\django_chat\venv\lib\site-packages\environ\environ.py", line 212, in str value = self.get_value(var, cast=str, default=default) File "C:\Users\user\Documents\django_chat\venv\lib\site-packages\environ\environ.py", line 391, in get_value raise ImproperlyConfigured(error_msg) from excdjango.core.exceptions.ImproperlyConfigured: Set the OPENAI_API_KEY environment variable>>>
-
해결됨홍정모의 따라하며 배우는 C언어
6-11 질문
안녕하세요! 다음 코드를 제 스스로 분석해봤는데, 정확한 분석이 맞는지 헷갈려서 질문드립니다.(1)Comma 연산자는 Assignment 연산자보다 서열이 낮은 것으로 알고 있습니다.1번 예시에서 콤마가 작동하는 시기는 z에 x의 값이 대입되고, y에 값 2가 대입된 뒤인가요?콤마 연산자는 왼쪽에서 오른쪽으로 계산을 하는데, 이미 대입연산자에 의해 각각 값이 대입된 변수 z와 y를 또 계산한다는 것이 잘 이해되지 않습니다.이 경우의 콤마 연산자의 계산이란 무엇인지 알려주시면 감사하겠습니다. (2)1번 예시와 2번 예시의 차이점은 무엇이 먼저 계산되느냐 일까요?즉 1번 예시에서는 x에 1이 대입되고, 그 값이 다시 x에 대입된 뒤, y에 2가 대입되고, 콤마 연산자가 작동한다면, 2번 예시에서는 x에 1이 대입되고, y에 2가 대입된 뒤, x의 값이 z에 대입되고, 콤마 연산자가 작동하는 건가요? 늘 친절한 답변 감사합니다.
-
미해결모의해킹 실무자가 알려주는, SQL Injection 공격 기법과 시큐어 코딩 : PART 1
sqlplus
어제까지는 잘 되다가, 오늘 갑자기 안켜지네요. sqlplus. 이럴 때는 어떻게 해야 하나요?