회원테이블 JwtFilter,JwtUtil,TokenTable포함(회원 정보 수정,회원 정보 조회,회원탈퇴, 비밀번호 변경, 로그인,회원가입)

HUGO·2022년 9월 28일
0

JWT

목록 보기
4/4

TokenMapper.java에 소스 추가

// 토큰 정보 가져가기
    package com.example.mapper;

import org.apache.ibatis.annotations.Mapper;

import com.example.dto.TokenDTO;

@Mapper
public interface TokenMapper {
    
    // 토큰 정보를 추가 또는 수정하기
    public int upsertToken(TokenDTO obj);

    // 토큰 정보 가져가기
    public TokenDTO selectTokenOne(String userid);

    public int deleteToken(String userid);
}

tokenMapper.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.mapper.TokenMapper">


    <select id="selectTokenOne" parameterType="String" 
        resultType="com.example.dto.TokenDTO">
        SELECT T.* FROM TOKENTBL T WHERE USERID=#{userid}
    </select>

    <insert id="upsertToken" parameterType="com.example.dto.TokenDTO">
        MERGE INTO
            TOKENTBL                                 <!-- 토큰테이블에 USERID가 일치 하는게 있다면 TOKEN, REGDATE를 업데이트 하고 -->
        USING DUAL              
            ON USERID=#{userid}
        WHEN MATCHED THEN
            UPDATE SET TOKEN=#{token}, REGDATE=CURRENT_DATE
        WHEN NOT MATCHED THEN                                   <!-- 없다면 USERID,TOKEN,REGDATE를 추가한다 -->
            INSERT (USERID, TOKEN, REGDATE ) VALUES(#{userid},#{token}, CURRENT_DATE)
    </insert>

<!--회원 탈퇴에 쓸 것.-->
    <delete id="deleteToken" 	parameterType="com.example.dto.TokenDTO">
    DELETE FROM TOKENTBL WHERE USERID=#{userid}
    </delete>

</mapper>

(회원 정보 수정) MemberRestController.java

@PutMapping(value = "/update.json")
    public Map<String, Object> updatePUT(
        @RequestBody MemberDTO member, 
        HttpServletRequest request, 
        HttpServletRequest httpServletRequest){
        Map<String, Object> retMap = new HashMap<>();
        try {
            // 필터로 전송된 아이디 값 꺼내기
            String userid = (String)request.getAttribute("userid");
            member.setUserid(userid);
            System.out.println(userid.toString());

            int ret = mMapper.updateMember(member);

            retMap.put("ret", ret);
            retMap.put("status", 200);
        } catch (Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;
    }

(회원 정보 수정) memberMapper.xml

<update id="updateMember" parameterType="com.example.dto.MemberDTO">
          UPDATE MEMBERTBL SET 
               AGE=#{age} 
               <if test="phone != null">        <!-- 한개만 바꿔도 되고 두개만 바꿔도 되고 이럴땐 if 문으로-->
                    , PHONE=#{phone}
               </if>
               <if test="gender != null">
                    , GENDER=#{gender}
               </if>     
          WHERE
               USERID=#{userid}
     </update>

(회원 정보 수정) MemberMapper.java

// 회원 정보 수정
    public int updateMember(MemberDTO member);

(암호 변경) MemberDTO.java

package com.example.dto;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

// Map의 장점 변수 지정할 필요 없음 
// 단점 : 형변환을 해야 함.
// mybatis에서는 그저 아무 의미없이 값을 보관하는 Map<String, Object> map

// DTO의 장점
// type이 정의 되어 있음
// 단점 : 필요시 변수를 만들어야 함.

@Getter // mybatis Mapper에서 사용함
@Setter // view에서 사용
@ToString() // 현재 객체의 내용 확인용
@NoArgsConstructor // 생성자
@AllArgsConstructor
public class MemberDTO {
    String userid;
    String userpw;
    int age;
    String phone;
    String gender;
    Date regdate;
    String role;

    int block = 1;

    String userpw1; // 암호변경을 위해 추가
}

(암호 변경) MemberRestController.java

@PutMapping(value="/updatepw.json")
    public Map<String, Object> updatepwPUT(
        @RequestBody MemberDTO member,
        @RequestHeader(name = "TOKEN") String token) {
        Map<String, Object> retMap = new HashMap<>();
        try {
            String userid = jwtUtil.extractUsername(token);
            member.setUserid(userid);
            member.setUserpw1( bcpe.encode(member.getUserpw1()) );

            System.out.println("=====================");
            System.out.println(member.toString());
            System.out.println("=====================");
            System.out.println(token.toString());
            System.out.println("=====================");

            // 아이디를 이용해서 현재 암호를 가져옴.
            MemberDTO member1 = mMapper.selectMemberOne(userid);

            System.out.println(member1.toString());
            System.out.println("=====================");
            // 입력한 암호, hash된 DB암호 비교
            System.out.println(member.getUserpw());
            System.out.println("=====================");
            System.out.println(member1.getUserpw());
            if(bcpe.matches(member.getUserpw(), member1.getUserpw())){
                int ret = mMapper.updateMemberPw(member);
                retMap.put("result", ret);
            }
            retMap.put("status", 200);
        }
        catch(Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;  
    }

(암호 변경) MemberMapper.java에 소스 추가

// 암호 변경
    public int updateMemberPw(MemberDTO member);

(암호 변경) memberMapper.xml

<update id="updateMemberPw" parameterType="com.example.dto.MemberDTO">
               UPDATE MEMBERTBL SET USERPW=#{userpw1} WHERE USERID=#{userid}
          </update>

PutMapping과 Update query문으로 값을 null로 만들 예정

(회원 탈퇴) MemberRestController.java

@PutMapping(value="/delete.json")
    public Map<String, Object> deletePUT(
        @RequestBody MemberDTO member,
        @RequestHeader(name = "TOKEN") String token) {
        Map<String, Object> retMap = new HashMap<>();
        try {
            String userid = jwtUtil.extractUsername(token);
            member.setUserid(userid);

            System.out.println("=====================");
            System.out.println(member.toString());

            // 아이디를 이용해서 현재 암호를 가져옴.
            MemberDTO member1 = mMapper.selectMemberOne(userid);
            System.out.println("=========================");
            System.out.println(member1.toString());

            // 입력한 암호, hash된 DB암호 비교
            if(bcpe.matches(member.getUserpw(), member1.getUserpw())){
                // MEMBERTBL에서 사용자 정보를 변경
                int ret = mMapper.deleteMember(member);
                // UPDATE MEMBERTBL SET AGE=0, PHONE=null, GENDER =null WHERE USERID=#{userid}

                // TOKENTBL에 userid에 해당하는 항목 삭제
                int ret1 = tMapper.deleteToken(userid);
                // DELETE FROM TOKENTBL WHERE USERID=#{userid}
                
                retMap.put("result", ret);
                retMap.put("token", ret1);
            }

            retMap.put("status", 200);
        }
        catch(Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;  
    }

(회원 탈퇴) MemberMapper.java에 소스 추가

// 회원 삭제
    public int deleteMember(MemberDTO member);

(회원 탈퇴) memberMapper.xml

<update id="deleteMember" parameterType="com.example.dto.MemberDTO">
               UPDATE MEMBERTBL SET AGE=0, PHONE=null, GENDER=null WHERE USERID=#{userid}
</update>

(로그인) MemberRestController.java

 @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);

            String token = jwtUtil.generateToken(member.getUserid());
            // TOKENTBL에 아이디가 존재 한다면 insert 없으면 update를 한 다음 토큰 전송(어떤 아이디가 어떤 토큰을 발행 했는지 토큰을 관리 해야 함.)

            TokenDTO obj = new TokenDTO();
            obj.setUserid(member.getUserid());
            obj.setToken(token);
            int ret = tMapper.upsertToken(obj);

            retMap.put("status", 200);
            if (ret == 1) {
                retMap.put("token", token);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            retMap.put("status", -1);
        }
        return retMap;
    }

(로그인) MemberMapper.java

  public MemberDTO selectMemberOne(String userid);

(로그인) memberMapper.xml

 <select id="selectMemberOne" parameterType="String" resultType="com.example.dto.MemberDTO">
                SELECT M.* FROM MEMBERTBL M WHERE M.USERID=#{userid}
        </select>

(회원가입) MemberRestController.java

@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;
    }
}

(회원가입) MemberMapper.java

// 여기를 생략했기 때문에 XML 에서 찾아서 자동으로 수행됨.
    public int joinMember ( MemberDTO member );

(회원가입) memberMapper.xml

<insert id="joinMember" parameterType="com.example.dto.MemberDTO">
                INSERT INTO MEMBERTBL(USERID, USERPW, AGE, PHONE, GENDER, REGDATE, ROLE)
                VALUES(#{userid}, #{userpw}, #{age}, #{phone}, #{gender}, CURRENT_DATE, #{role})
</insert>

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;

import com.example.dto.TokenDTO;
import com.example.mapper.TokenMapper;


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

    @Autowired TokenMapper tMapper;
    @Autowired JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(
            HttpServletRequest request, 
            HttpServletResponse response, 
            FilterChain filterChain) throws ServletException, IOException {
        try {
            System.out.println("=======filter============");
            System.out.println(request.getRequestURI());
            System.out.println("=======filter============");

            System.out.println("=======Token============");
            String token = request.getHeader("TOKEN");
            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();
            }

            // 세션에 저장된 토큰과 현재 토큰이 같은 것인지 확인
            TokenDTO obj = tMapper.selectTokenOne(userid);
            if(!obj.getToken().equals(token)){
                throw new Exception();
            }

            // 필터 요소 
            
            // restcontoller에 전달하고 싶은 값들
            request.setAttribute("userid", userid);

            // restcontroller로 실행
            filterChain.doFilter(request, response);
        }
        catch(Exception e) {
            e.printStackTrace();
            response.sendError(-1, "token error");
        }
    }
}

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());
    }

    

}
profile
갓 신생아 개발자 이야기

0개의 댓글