백엔드는
jwtfilter
에서 토큰 발행여부를 확인하고 토큰으로 사용자의 정보를 확인한다
발행된 토큰 정보를 DB에 보관하여 필요할때마다 꺼내써야한다
추후에 소셜로그인 사용시에도 일반 로그인과 동일하게 토큰발행 정보를 저장하여 보관해야 한다
사용자가 로그아웃시는 저장된 토큰은 삭제 처리 해준다
토큰 DB에 저장시
➡️ DB에 이미userid
가 존재하면 새로 발행된token
정보와 발행시간을 갱신하여update
DB에 이미userid
가 존재하지 않으면userid
와token
, 발행된 시간을insert
token
이 DB에 저장되는 과정이 REST에서세션
과 같다
토큰 정보 보관용 테이블 생성
- 사용자아이디 = 기본키
- 토큰정보보관
- 토큰발행일
**CREATE TABLE TOKENTBL(
USERID VARCHAR2(30) CONSTRAINT PK_TOKEN_ID PRIMARY KEY,
TOKEN VARCHAR2(200) NOT NULL,
REGDATE TIMESTAMP DEFAULT CURRENT_DATE,
CONSTRAINT FK_TOKENTBL_USERID FOREIGN KEY(USERID) REFERENCES MEMBERTBL(USERID)
);**
package com.example.dto;
import java.util.Date;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@NoArgsConstructor
public class TokenDTO {
String userid;
String token;
Date regdate;
}
로그인시 발행된 토큰 저장하기
➡️ 로그인시 DB에 토큰 저장하지 않았을땐 생성된 토큰을 map에 바로 넣어 리턴해줬었는데,
DB에 저장하여 사용하기 위해 DB에 먼저 저장하고 토큰을 리턴해준다
retMap.put("token",jwtUtil.generateToken(member.getUserid()));
로그인시 TokenMapper 호출해서 정보 담기
DB에서 발행된 토큰의 userid , token정보, token발행일을 확인할 수 있다
토큰 저장
TokenDTO obj = new TokenDTO();
obj.setUserid(member.getUserid());
obj.setToken(token);
int ret = tmapper.upsertToken(obj);
토큰 DB저장 후 토큰 리턴
if(ret ==1){
// 토큰발행 성공한 경우
retMap.put("token", token);
}
// 로그인하기
// 127.0.0.1:8080/BOOT1/api/member/login.json
// {"userid":"c1", "userpw":"c1", "role":"CUSTOMER"}
@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에 추가한 다음 map에 반환
// token이 존재하지 않는경우 insert, token이 존재하는 경우 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;
}
@Mapper
public interface TokenMapper {
// 토큰 정보를 추가 또는 수정하기
public int upsertToken(TokenDTO obj);
}
USERID 조건이 있다면 UPDATE수행 ➡️ TOKEN과 REGDATE 정보 갱신
USERID 조건이 없다면 INSERT수행 ➡️ USERID 와 TOKEN, REGDATE정보 입력
MERGE INTO 구문 사용하여 SQL문 작성한다
<mapper namespace="com.example.mapper.TokenMapper">
<!-- 토큰 정보를 추가 또는 수정하기 -->
<insert id="upsertToken" parameterType="com.example.dto.TokenDTO">
MERGE INTO
TOKENTBL
USING DUAL
ON USERID=#{userid}
WHEN MATCHED THEN
UPDATE SET TOKEN=#{token}, REGDATE=CURRENT_DATE
WHEN NOT MATCHED THEN
INSERT (USERID, TOKEN, REGDATE) VALUES(#{userid}, #{token}, CURRENT_DATE )
</insert>
</mapper>
userid입력시 토큰정보 반환
// 토큰 정보 조회하기
public TokenDTO selectTokenOne(String userid);
토큰정보 조회
<select id="selectTokenOne" parameterType="String" resultType="com.example.dto.TokenDTO">
SELECT T.* FROM TOKENTBL T WHERE USERID=#{userid}
</select>
mapper에서 생성한 selectTokenOne을 이용하여 ➡️ 토큰 일치 여부 확인
// 토큰 호출시 DB에 존재하는지 여부 확인
@Autowired
TokenMapper tmapper;
// DB에 저장된 토큰과 현재 토큰이 같은 것인지 확인
TokenDTO obj = tmapper.selectTokenOne(userid);
// !=not 같지 않은경우
if(!obj.getToken().equals(token)){
throw new Exception(); //오류로 보내기
}
회원정보 수정시 업데이트 하지 않는 항목은 그대로 유지하기
조건 = 나이는 필수변경! 연락처/성별은 필수변경 사항이 아님
➡️ 1개 이상의 항목은 반드시 변경해주어야한다
1개도 변경 안하면 update 하는 의미가 없으니..!
UPDATE MEMBERTBL
SET
AGE=#{age}, PHONE=#{phone}, GENDER=#{gender}
WHERE
USERID=#{userid}
위의 쿼리문은 update정보를 입력하지 않은 항목에 대해 기존정보를
null
로 바꿔버린다
💡 if문 사용하여 update정보 미입력시 기존정보 유지하도록 해준다
쿼리문 작성시 if문을 사용하면 동적으로 DB변경 가능!
➡️ if문에 해당하면 쿼리문에 포함되고 해당하지 않으면 쿼리문에 포함되지 않는다
<update id="updateMember" parameterType="com.example.dto.MemberDTO">
UPDATE MEMBERTBL SET
AGE=#{age}
<if test="phone != null">
, PHONE=#{phone}
</if>
<if test="gender != null">
, GENDER=#{gender}
</if>
WHERE
USERID=#{userid}
</update>
📌 서비스시에는 userid 기준으로 잡고 나머지 변경된 항목만 저장되게 해도 된다!
<!-- 회원정보 수정하기 -->
<update id="updateinfoMember" parameterType="com.example.dto.MemberDTO">
UPDATE MEMBERTBL SET
USERID=#{userid}
<if test="age != null">
, AGE=#{age}
</if>
<if test="phone != null">
, PHONE=#{phone}
</if>
<if test="gender != null">
, GENDER=#{gender}
</if>
WHERE
USERID=#{userid}
</update>
실제로 수행해보니 고정된 ID 정보 제외하고 사용자가 변경한 항목만 정보 수정이 가능하고,
변경되지 않은 나머지 항목들은 기존값을 유지하고 있다
하이버네이트
= JPA
에서는 DTO에 새 암호 변수를 생성하는 경우 DB에 컬럼이 하나 생기는 문제가 발행한다
반면에 마이바티스는 쿼리문에 의해 컬럼이 만들어진다
마이바티스에서 DTO = map으로 생각하면 된다
= 즉, 값을 보관하는 객체일 뿐, 아무 의미 없으며, DTO로 DB연동이 되지 않는다!
⇒ 변수 지정할 필요 없음! 새로 변수를 만들지 않아도 사용가능하다
⇒ 사용시 형변환을 해야 함
⇒ type이 정의되어 있어 편리함
⇒ 필요시마다 DTO에 변수를 생성해야 함
lombok이 없었던 라떼는… getter/setter 지우며 썼다..
소스 코드의 혁신은 번거로움⇒짜증의 증가?.. 새로운 기능이 개발에서 생성됨
➡️ 상황에 따라 다르지만 보편적으로 DTO가 좋다!(권장)
소규모, 혼자한다면 map사용해도 무방하지만
대규모, 여러사람이 같이 작업 하는 경우 명확한 기준이 필요하기 때문에 DTO 사용을 권장한다
로직
1.token
에서 가져온userid
넣어주기
2. 변경할 비밀번호 암호화 하여member.setNewpw
에 넣기
3. 기존 회원정보 조회하여 회원정보에서 DB에 저장된 암호 가져오기
4. 사용자가 view에 입력한 암호와 DB에 존재하는 해당 사용자의 암호가 일치하는지 비교
=bcpe.matches("rawPassword = 현재암호", "encodedPassword = DB암호")
5. 4.가 일치하는 경우 사용자가 입력한 변경할 암호를 기존userpw
에 넣어 암호를 변경해준다
// 127.0.0.1:8080/BOOT1/api/member/updatepw.json
// 암호변경 /updatepw.json
@PutMapping(value = "/updatepw.json")
public Map<String, Object> updatepwPUT(
@RequestHeader(name = "TOKEN") String token, @RequestBody MemberDTO member
){
Map<String, Object> retMap = new HashMap<>();
try {
// 생성한 TOKEN을 이용하여 userid를 가져옴
String userid = jwtUtil.extractUsername(token);
BCryptPasswordEncoder bcpe = new BCryptPasswordEncoder();
member.setUserid(userid); //token에서 가져온 userid넣어주기
member.setNewpw(bcpe.encode(member.getNewpw())); //바꿀 비밀번호 암호화 하여 넣어주기
System.out.println("===================member.toString()" + member.toString());
// 기존 회원정보 조회
// = 로그인된 사용자의 토큰을 이용하여, 아이디를 가져온 후 정보조회
MemberDTO member1 = mmapper.selectMemberOne(userid);
// 입력한 암호, hash된 DB암호 비교
if(bcpe.matches( member.getUserpw() , member1.getUserpw() )){
System.out.println("=======member.getUserpw()" + member.getUserpw());
System.out.println("=======member1.getUserpw()" + member1.getUserpw());
int ret = mmapper.updateMemberPw(member);
// 암호가 변경된 경우
retMap.put("result", ret);
}
// if문이 실행된 후 상태(status)값 전달
retMap.put("status", 200);
} catch (Exception e) {
e.printStackTrace();
retMap.put("status", -1);
}
return retMap;
}
public int updateMemberPw(MemberDTO member);
변경될 암호
newpw
값을USERPW
에 넣어주어야 한다 ➡️USERPW=#{newpw}
<update id="updateMemberPw" parameterType="com.example.dto.MemberDTO">
UPDATE MEMBERTBL SET USERPW=#{newpw} WHERE USERID=#{userid}
</update>
- 다른 테이블에 외래키가 연결되어있어 회원을 완전히 삭제 할 수는 없다
사용자에게 삭제한것처럼만 보이면 된다
➡️ 회원의 정보를 타입에 따라null
또는0
으로 바꿔준다- BLOCK값도 0으로 날려줘야 한다
BLOCK값이 1인경우 = 차단안됨 / 0인경우 = 차단됨- 회원탈퇴 조건 ➡️ 회원탈퇴시 사용자가 암호를 입력한다고 가정한다
// 127.0.0.1:8080/BOOT1/api/member/delete.json
// 회원탈퇴 /delete.json
// 암호 입력한다고 가정
@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);
// 입력한 암호, hash된 DB암호 비교
if(bcpe.matches(member.getUserpw(), member1.getUserpw())){
// MEMBERTBL에서 사용자 정보를 변경 = null,0 으로 변경 (update)
int ret = mmapper.deleteMemberOne(member);
// TOKENTBL에 userid에 해당하는 항목 삭제 (delete)
int ret1 = tmapper.deleteToken(userid);
retMap.put("result", ret);
}
retMap.put("status", 200);
}
catch(Exception e) {
e.printStackTrace();
retMap.put("status", -1);
}
return retMap;
}
// 회원 탈퇴
public int deleteMemberOne(MemberDTO member);
사용자에게 삭제한것처럼만 보여야 하니
➡️ 회원의 정보를 null 또는 0으로 변경한다(BLOCK값도 0으로 변경)
<!-- 회원 탈퇴하기 -->
<update id="deleteMemberOne" parameterType="com.example.dto.MemberDTO">
UPDATE MEMBERTBL SET USERPW=null, AGE=0, PHONE=null,
REGDATE=null, ROLE=null, GENDER=null, BLOCK=0
WHERE USERID=#{userid}
</update>
✔️ 결과
회원 탈퇴 전
회원 탈퇴 후