JWT Security

HUGO·2022년 9월 27일
0

JWT

목록 보기
2/4

Boot20220915Application.java (서버 돌리는 용)

package com.example.boot_20220915;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

// 서비스(service), 컨트롤러(controller), 환경설정(config)
@ComponentScan(basePackages = {
	"com.example.service", 
	"com.example.controller",
	"com.example.restcontroller",
	"com.example.config",
	"com.example.handler",
	// Field jwtUtil in com.example.restcontroller.MemberRestController required a bean of type 'com.example.jwt.JwtUtil' that could not be found.
	// 이게 문제 였음. 이거 안넣으면 위에 처럼 오류남.
	"com.example.jwt"
})

// @WebFilter
@ServletComponentScan(basePackages = "com.example.jwt")

// mybatis => mapper
@MapperScan(basePackages = "com.example.mapper")


@EnableRedisHttpSession
@SpringBootApplication



public class Boot20220915Application {

	public static void main(String[] args) {
		SpringApplication.run(Boot20220915Application.class, args);
	}

}

/jwt/JwtUtil.java


package com.example.jwt;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;


import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtUtil {

    // 토큰 생성용 보안키
    private final String SECRETKEY = "fekjkfe43jfe";

    // 정보 추출용 메소드
    private <T> T extractClaim(String token, Function<Claims, T> claimsResolver){
        final Claims claims = Jwts.parser().setSigningKey(SECRETKEY).parseClaimsJws(token).getBody();
        return claimsResolver.apply(claims);
    }

    // 토큰 생성(아이디 정보를 이용한 토큰 생성)
    public String generateToken(String username) {
        System.out.println(username);
        
        // ex) 30분 => 1000 * 60 * 30
        long tokenValidTime = 1000 * 60 * 60 * 4; // 4시간

        Map<String, Object> claims = new HashMap<>();
        String token = Jwts.builder().setClaims(claims).setSubject(username)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + tokenValidTime))
                .signWith(SignatureAlgorithm.HS256, SECRETKEY).compact();

        return token;
    }

    // 토큰 검증
    public Boolean validateToken(String token, String userid){
        // 토큰에서 아이디 정보 추출
        final String username = this.extractUsername(token);
        if (username.equals(userid) && !isTokenExpired(token)) {
            return true;
        }
        return false;
    }

    // 토큰에서 아이디 정보 추출하기
    public String extractUsername(String token){
        return extractClaim(token, Claims::getSubject);
    }

    // 토큰에서 만료 시간 추출하기
    public Date extractExpiration(String token){
        return extractClaim(token, Claims::getExpiration);
    }
    
    // 토큰의 만료시간이 유효한지 확인
    public Boolean isTokenExpired(String token){
        // 만료시간 가져와서 현재시간보다 이전인지 확인
        return this.extractExpiration(token).before(new Date());
    }

    

}

JwtFilter.java

package com.example.jwt;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.filter.OncePerRequestFilter;


//필터를 적용하는자 하는 url설정
@WebFilter(urlPatterns = {
    "/api/member/update.json",
    "/api/member/updatepw.json",
    "/api/member/delete.json"
})
public class JwtFilter extends OncePerRequestFilter {

    @Autowired JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(
            HttpServletRequest request, 
            HttpServletResponse response, 
            FilterChain filterChain) throws ServletException, IOException {
        try {
            System.out.println("=======filter============"); //filter 들어 왔는지 확인
            System.out.println(request.getRequestURI());
            System.out.println("=======filter============");

            String token = request.getHeader("TOKEN");
            System.out.println("=============TOKEN============="); // token 들어 왔는지 확인
            System.out.println(token.toString());
            System.out.println("=============TOKEN=============");
            if(token == null || token.length() == 0) {
                throw new Exception(); // 강제로 오류발생 시킴
            }

            String userid = jwtUtil.extractUsername(token);
            if(jwtUtil.validateToken(token, userid) == false){
                throw new Exception();
            }
            
            // 아래 라인이 실행되어야 restcontroller로 넘어감
            filterChain.doFilter(request, response);
        }
        catch(Exception e) {
            e.printStackTrace();
            response.sendError(-1, "token error");
        }
    }
}

MemberRestController.java

package com.example.restcontroller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.dto.MemberDTO;
import com.example.jwt.JwtUtil;
import com.example.mapper.MemberMapper;


@RestController
@RequestMapping(value = "/api/member")
public class MemberRestController {
    
    @Autowired MemberMapper mMapper;
    @Autowired JwtUtil jwtUtil; //컴포넌트 객체 생성

    @Autowired PasswordEncoder bcpe;

    //Security에서 @Bean으로 객체를 생성했기 때문에 사용가능
    @Autowired AuthenticationManager authenticationManager;


    

    // 회원 정보 수정 => 127.0.0.1:8080/BOOT1/api/member/update.json
    @PutMapping(value = "/update.json")
    public Map<String, Object> updatePUT(){
        Map<String, Object> retMap = new HashMap<>();
        try {
            retMap.put("status", 200);
        } catch (Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;
    }



    // 127.0.0.1:8080/BOOT1/api/member/login.json
    // application/json
    @PostMapping(value="/login.json")
    public Map<String, Object> loginPOST(
            @RequestBody MemberDTO member){
        System.out.println(member.toString());
        Map<String, Object> retMap = new HashMap<>();
        try {
            // string 권한으로 collection으로 변경
            String[] strRole = { member.getRole() };
            Collection<GrantedAuthority> role 
                = AuthorityUtils.createAuthorityList(strRole);
            
            //CustomDetailsService와 같은 역할
            UsernamePasswordAuthenticationToken
                upat = new UsernamePasswordAuthenticationToken(
                    member.getUserid(), member.getUserpw(), role);
            authenticationManager.authenticate(upat);

            retMap.put("status", 200);
            retMap.put("token", jwtUtil.generateToken(member.getUserid()));
        }
        catch(Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;
    }
    
    

    // 127.0.0.1:8080/BOOT1/api/member/join.json
    @PostMapping(value="/join.json")
    public Map<String, Object> joinPOST(
            @RequestBody MemberDTO member) {
        Map<String, Object> retMap = new HashMap<>();         
        System.out.println(member.toString());       
        try {
            // 암호변경후 저장
            member.setUserpw( bcpe.encode(member.getUserpw() ) );

            int ret = mMapper.joinMember(member);
            retMap.put("status", 200);
            retMap.put("result", ret);
        }
        catch(Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;
    }
    
}
profile
갓 신생아 개발자 이야기

0개의 댓글