로그인 시 토큰/발행 생성 위해 jwtutil사용하여 토큰 발행
package com.example.jwt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
// jjwt
// 토큰을 생성하고, 토큰의 정보를 추출 또는 만료시간 검증
@Component
public class JwtUtil {
// 토큰 생성용 보안키
private final String SECRETKEY = "gyuf6r567546sd546e56";
// 정보 추출용 메소드
private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = Jwts.parser().setSigningKey(SECRETKEY).parseClaimsJws(token).getBody();
return claimsResolver.apply(claims);
}
// 토큰 생성(아이디 정보를 이용한 토큰 생성)
// 아이디만포함. json -> string -> 토큰 -> string -> json
// {"uid":"aaa", "role":"CUSTOMER"}
public String generateToken(String username, String role) {
// 1. jsonobject로 변환
JSONObject jobj = new JSONObject();
jobj.put("username", username);
jobj.put("role", role);
// ex) 30분 => 1000 * 60 * 30
long tokenValidTime = 1000 * 60 * 60 * 4; // 4시간
// 2. 문자형태로 추가한 후 토큰 생성
Map<String, Object> claims = new HashMap<>();
String token = Jwts.builder().setClaims(claims)
.setSubject(jobj.toString())
.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) {
String sObj = extractClaim(token, Claims::getSubject);
JSONObject jobj = new JSONObject(sObj);
return jobj.getString("username");
}
// 토큰에서 권한 정보 정보 추출하기
public String extractRole(String token) {
String sObj = extractClaim(token, Claims::getSubject);
JSONObject jobj = new JSONObject(sObj);
return jobj.getString("role");
}
// 토큰에서 만료 시간 추출하기
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
// 토큰의 만료시간이 유효한지 확인
public Boolean isTokenExpired(String token) {
// 만료시간 가져와서 현재시간보다 이전인지 확인
return this.extractExpiration(token).before(new Date());
}
}
토큰을 전송해서 검증 후에 수행되어야 하는 주소들
토큰 검증 완료 = 로그인이 완료되었다는것
로그아웃, 회원 한명 조회 , 회원정보 수정, 회원 탈퇴
⇒ 위 4개는 필터를 통해 토큰 검증이 완료된 후 수행되어야 한다
@component
를 붙이면 = 모두 filter를 통과한다
⇒ filter가 필요한 주소만 지정하기 위해 filterConfig 생성하여 filter환경설정을 해준다
filterConfig 에서 filter 무시할 주소 설정
package com.example.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.jwt.JwtFilter;
// 필터를 통과할 url설정하기
@Configuration
public class FilterConfig {
@Bean
// <JwtFilter> => 사용할 필터 명시
public FilterRegistrationBean<JwtFilter>
filterRegistrationBean(JwtFilter jwtFilter){
FilterRegistrationBean<JwtFilter> bean
= new FilterRegistrationBean<>();
// bean.setFilter(jwtFilter); => 아래 설정한 bean.addUrlPatterns에 적용할 필터 설정
bean.setFilter(jwtFilter);
// ex) 필터를 통과시킬 URL설정하기
// 하위 모든 주소일 경우 * 사용!
// "/api/board/*"
bean.addUrlPatterns(
"/api/member/update.json",
"/api/member/logout.json",
"/api/member/delete.json",
"/api/member/selectone.json"
);
return bean;
}
}
package com.example.restcontroller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.entity.ExMember;
import com.example.jwt.JwtUtil;
import com.example.repository.ExMemberRepository;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping(value = "/api/member")
@RequiredArgsConstructor
public class MemberRestController {
// 환경설정에서 미리 생성된 bean객체 가져오기 = autowired = 주입
// SecurityConfig.java 에서 생성한 암호화 bean객체 가져오기
final PasswordEncoder passwordEncoder;
final AuthenticationManager authenticationManager;
final ExMemberRepository exMemberRepository;
final JwtUtil jwtUtil;
// 127.0.0.1:8080/ROOT/api/member/join.json
@PostMapping(value = "/join.json")
public Map<String, Object> joinPOST(@RequestBody ExMember member){
Map<String, Object> map = new HashMap<>();
try {
System.out.println(member.toString());
// 회원가입시 사용자가 입력한 암호가져와서 암호화
member.setPw(passwordEncoder.encode(member.getPw()));
exMemberRepository.save(member);
map.put("status", 200);
} catch (Exception e) {
map.put("status", -1);
map.put("result", e.getMessage());
}
return map;
}
// 127.0.0.1:8080/ROOT/api/member/logout.json
@PostMapping(value = "/logout.json")
public Map<String, Object> logoutPOST(){
Map<String, Object> map = new HashMap<>();
try {
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
// 127.0.0.1:8080/ROOT/api/member/selectone.json
@GetMapping(value = "/selectone.json")
public Map<String, Object> selectoneGET(HttpServletRequest request){
Map<String, Object> map = new HashMap<>();
try {
// 토큰 검증 후에 추출하는 사용자의 아이디 정보
String id = (String) request.getAttribute("username");
ExMember member = exMemberRepository.findById(id).orElse(null);
map.put("status", 200);
map.put("result", member);
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
// 127.0.0.1:8080/ROOT/api/member/update.json
@PostMapping(value = "/update.json")
public Map<String, Object> updatePUT(){
Map<String, Object> map = new HashMap<>();
try{
}
catch(Exception e){
}
return map;
}
// 127.0.0.1:8080/ROOT/api/member/delete.json
@PostMapping(value = "/delete.json")
public Map<String, Object> deleteDELETE(){
Map<String, Object> map = new HashMap<>();
try{
}
catch(Exception e){
}
return map;
}
// 로그인하기
// rest사용할거면 DetailUserService 사용할 필요 없움
// 127.0.0.1:8080/ROOT/api/member/login.json
// ex) {"id" : "aaa", "pw" : "aaa", "role" : "CUSTOMER"}
@PostMapping(value = "/login.json")
public Map<String, Object> loginPOST(@RequestBody ExMember member){
Map<String, Object> map = new HashMap<>();
try {
System.out.println(member.toString());
// 아이디를 이용하여 DB의 기존 회원정보 가져오기
ExMember retMember = exMemberRepository.findById(member.getId()).orElse(null);
if(retMember != null){
// Hash 되지 않은 암호와 DB에서 꺼낸 HASH된 암호 비교
if(passwordEncoder.matches(member.getPw(), retMember.getPw())){
// 카카오 같은 간편로그인은 토큰이 2개 발행된다
// 일반 토큰, refresh토큰
map.put("status", 200);
map.put("result", jwtUtil.generateToken(member.getId(), member.getRole()));
}
}
else{
map.put("status", -1);
map.put("result", "password or username not found");
}
} catch (Exception e) {
map.put("status", -1);
map.put("result", e.getMessage());
}
return map;
}
}