Spring (day-13)

김성국·2023년 6월 28일
0
post-custom-banner

■ 회원정보수정

// 회원탈퇴, 비밀번호 변경, 회원정보 수정 ... 로그인이 되어야 되는 모든 것.
// 회원정보수정 => 토큰을 주세요. 검증해서 성공하면 정보수정을 진행
@PostMapping(value="/update.json")
public Map<String, Object> updatePOST(@RequestHeader(name = "token") String token) {
    Map<String, Object> retMap = new HashMap<>();
    try {
        // 1. 토큰을 받아서 출력
        log.info("{}", token);

        // 2. 실패시 전달값
        retMap.put( "status", 0 );
        
        // 3. 토큰을 검증 후 성공
        if ( jwtUtil2.checkJwt(token) == true) {
            // 4. 정보를 수정함.
            retMap.put( "status", 200 );
        }
    } catch (Exception e) {
        e.printStackTrace(); 
        retMap.put( "status", -1 );
        retMap.put( "error", e.getMessage() );
    }
    return retMap;
}
  • 어제 수업시간때 생성했던 update.json응 사용한다.
// 토큰에 대해서 검증하고 데이터를 추출하는 메소드
public Student2 checkJwt(String token) throws Exception{
    try {
        // 1. key 준비
        byte[] keyBytes = DatatypeConverter.parseBase64Binary(BASEKEY);

        Claims claims = Jwts.parserBuilder()
            .setSigningKey(keyBytes)
            .build()
            .parseClaimsJws(token)
            .getBody();
        Student2 obj = new Student2();
        obj.setEmail( (String)claims.get("id") );
        obj.setName((String) claims.get("name"));
        return obj;
    } 
    catch(ExpiredJwtException e1) {
        System.err.println("만료시간 종료" + e1.getMessage());
        return null;
    }
    catch(JwtException e2) {
        System.err.println("토큰오류" + e2.getMessage());
        return null;
    }
    catch(Exception e) {
        System.out.println("e1과 e2 오류 아닌 모든 오류" + e.getMessage());
        return null;
    }
}
  • JwtUtil2.java를 위처럼 수정한다.


  • 로그인을 하여 토큰을 받는다. 이렇게 이름과 전화번호 변경하면 db에도 변한 것을 확인할 수 있다.

■ Filter

// 회원정보수정, 회원탈퇴, 비번번경 토큰이 필요한 경우에 대한 처리
// 컨트롤러 전에 수행되는 클래스 => 토큰의 유효성을 검증하고 실패 시 컨트롤러 진입X
// url 주소에 따라 분류함
@Component
@RequiredArgsConstructor
public class JwtFilter2 extends OncePerRequestFilter{
    
    final JwtUtil2 jwtUtil2;
    ObjectMapper objectMapper = new ObjectMapper(); // json으로 변환하는 라이브러리

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{
        try{
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");;
            Map<String, Object> retMap = new HashMap<>();
            
            String token = request.getHeader("token");
            if(token == null){ // {status:-1, message:"token null"}로 반환됨
                retMap.put("status", -1);
                retMap.put("message", "token null");
                String result = objectMapper.writeValueAsString(retMap);
                response.getWriter().write(result);
                return; // 메소드 종료
            }
            if( token.length() <= 0 ){ // {status:-1, message:"token is empty"}로 반환됨.
                retMap.put("status", -1);
                retMap.put("message", "token is empty");
                String result = objectMapper.writeValueAsString(retMap);
                response.getWriter().write(result);
                return; // 메소드 종료
            }

            Student2 obj = jwtUtil2.checkJwt(token);
            if( obj == null ){
                retMap.put("status", -1);
                retMap.put("message", "token error");
                String result = objectMapper.writeValueAsString(retMap);
                response.getWriter().write(result);
                return; // 메소드 종료
            }

            // 아래 명령어가 실행되어가 정상적인 컨트롤러로 진입 가능.
            filterChain.doFilter(request, response);
        }
        catch (Exception e){
            e.printStackTrace();
            response.sendError(-1, "token error");

        }
    }
}
  • example 아래에 filter 폴더를 생성하여 JwtFilter2.java를 생성한다.
@Configuration
@Slf4j
public class FilterConfig {
    
    @Bean // 서버가 구동될 때 자동으로 호출됨
    // JwtFilter2 필터가 적용되는 url을 설정
    public FilterRegistrationBean<JwtFilter2> filterRegistrationBean(JwtFilter2 jwtFilter){
        log.info("filter => {}", "filterConfig");

        FilterRegistrationBean<JwtFilter2> filterReg = new FilterRegistrationBean<>();
        filterReg.setFilter(jwtFilter);
        
        filterReg.addUrlPatterns("/api/student2/update.json");
        filterReg.addUrlPatterns("/api/student2/delete.json");

        // filterReg.addUrlPatterns("/api/student2/*"); // *는 전체url
        return filterReg;
    }
}
  • confing 폴더에 FilterConfig.java를 생성한다.

■ UrlFilter

@Slf4j
@Component
@RequiredArgsConstructor
public class UrlFilter extends OncePerRequestFilter{@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        try{
            // ex) /ROOT/api/student2/update.json?id=a
            String contextPath = request.getContextPath(); // /ROOT
            String path = request.getServletPath(); // /api/student2/update.json
            String query = request.getQueryString(); // id=a

            log.info("{},{},{}", contextPath, path, query);

            // url에 login, logout이 포함되지 않은 경우..
            if( !path.contains("login") && !path.contains("logout")){
                HttpSession httpSession = request.getSession();
                
                if(query == null){
                    httpSession.setAttribute("url", path);
                }
                else {
                    httpSession.setAttribute("url", path + "?" + query);
                }
            }

            filterChain.doFilter(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }   
    }
}
  • 로그인 후에 이전페이지로 되돌아 가기 위헤서 현재의 페이지를 저장하는 필터
  • 현재페이지 중에서 로그인, 로그아웃은 제외시킴
@Bean // 서버가 구동될 때 자동으로 호출됨
    // JwtFilter2 필터가 적용되는 url을 설정
    public FilterRegistrationBean<JwtFilter2> filterRegistrationBean(JwtFilter2 jwtFilter){
        log.info("filter => {}", "filterConfig");

...

@Bean // 서버가 구동될 때 자동으로 호출됨
public FilterRegistrationBean<UrlFilter> filterRegistrationBean(UrlFilter urlFilter){
    log.info("filter => {}", "filterConfig");

    FilterRegistrationBean<UrlFilter> filterReg = new FilterRegistrationBean1<>();
    filterReg.setFilter(urlFilter);
    
    filterReg.addUrlPatterns("/api/student2/*"); // *는 전체url
    return filterReg;
}
  • FilterConfig.java에 위 코드를 추가하여 @Bean을 사용하여 서버가 구동될 때 자동으로 호출된다.
  • JwtFilter2 필터가 적용되는 url을 설정한다.

■ 로그인

@GetMapping(value="/my/login.do")
public String mylogin(){
    return "/student2/mylogin";
}

@PostMapping(value="myloginaction.do")
public String myloginAction(@ModelAttribute Student2 obj) {
    try{
        log.info("{}", obj.toString());

        // DetailsService를 사용하지 않고 세션에 저장하기

        // 1. 기존 자료 읽기
        Student2 obj1 = s2Repository.findById(obj.getEmail()).orElse(null);

        // 2. 전달한 아이디와 읽은 데이터 암호 비교
        if( bcpe.matches(obj.getPassword(), obj1.getPassword()) ) {
            // 3. 세션에 저장할 객체 생성하기 (저장할 객체, null, 권한)

            String[] strRole = {"ROLE_STUDENT2"};
            Collection<GrantedAuthority> role = AuthorityUtils.createAuthorityList(strRole);

            User user = new User( obj.getEmail(), obj1.getPassword(), role); // 
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null);
            
            // 수동으로 세션에 저장
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            context.setAuthentication(authenticationToken);
            SecurityContextHolder.setContext(context);
        }
        
        return "redirect:/student2/home.do";
    } catch (Exception e) {
        e.printStackTrace();
        return "redirect:/home.do";
    }
}
  • DetailsService를 사용하지 않고 세션에 저장하기
  • 기본 자료를 읽어 전달한 아이디와 읽은 데이터 암호를 비교한다
  • 세션에 저장할 객체 생성하여(저장할 객체, null, 권한)을 관리한다.
  • 수동으로 세션에 저장한다.

  • 로그인이 정상적으로 실행된다.
post-custom-banner

0개의 댓글