반응형
그동안 로그인 유지에 세션을 사용하였었다.하지만 RestApi 는 stateless(상태 유지 안함)이기 때문에 세션과는 맞지 않는 특성을 가지고 있다. 그렇기 때문에 rest-api 에서는 로그인 유지로 token을 사용한다. 토큰에 정보를 담아서 암호화 ➡️ 복호화 한다. 인증을 통과한 유저에게 생성한 토큰을 주고, 유저는 받은 토큰을 요청 헤더에 담아서 보낸다.
사용방법
pom.xml에 의존성을 추가한다.
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
demo 패키지 밑에 패키지 생성, jwttokenprovide 파일을 넣어준다.
package com.example.demo.auth;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
import com.example.demo.shopmember.ShopmemberDto;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
@Component
public class JwtTokenProvider {
private final Long expiredTime = 1000 * 60L * 60L * 1L; // 유효시간 1시간 (토큰의 유효시간)
Key key = Keys.hmacShaKeyFor("qwerqwersdfdsdgfsdgsdgfsfgsgafFSGHDFHJGFJGDFHSFGHSGFGDHFGJFGHJGFHJFHSFHDFGJHGJSFHSDHDHJFGHJGFHSFHGSFGHDFfgsdf".getBytes(StandardCharsets.UTF_8));
//cd값으로 넣어줄 토큰 값. 아무거나 막 친거임. 265비트 이상으로 안하면 오류남. 암호화에 사용할 키 값임
//토큰 생성기
public String generateJwtToken(ShopmemberDto member) {
Date now = new Date();
return Jwts.builder().setSubject(member.getId()) // 보통 username. id를 subject로 해줌
.setHeader(createHeader())
.setClaims(createClaims(member)) // 클레임, 토큰에 포함될 정보
.setExpiration(new Date(now.getTime() + expiredTime)) // 만료일
.signWith(key, SignatureAlgorithm.HS256)
.compact(); //암호화
}
//헤더 셋팅
private Map<String, Object> createHeader() {
Map<String, Object> header = new HashMap<>();
header.put("typ", "JWT"); //토큰 종류 설정
header.put("alg", "HS256"); // 해시 256 사용하여 암호화
header.put("regDate", System.currentTimeMillis()); //생성시간
return header;
}
//토큰에 추가 정보 셋팅
private Map<String, Object> createClaims(ShopmemberDto member) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", member.getId()); // 로그인 id
claims.put("roles", member.getType()); // 인가정보. usertype(판매자, 구매자) 타입숫자 값을 담아줌
return claims;
}
private Claims getClaims(String token) {
return Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
}
//토큰에 저장한 로그인 id값 꺼내서 반환
public String getUsernameFromToken(String token) {
return (String) getClaims(token).get("username");
}
//토큰에 저장한 로그인 type값 꺼내서 반환
public int getRoleFromToken(String token) {
return (int) getClaims(token).get("roles");
}
}
Controller에 토큰이 필요한 곳에 추가한다.
@PostMapping("/login")
public Map login(String id, String pwd) {
Map map = new HashMap();
boolean flag = false;
ShopmemberDto dto = service.getMember(id);
if (dto != null && pwd.equals(dto.getPwd())) {
String token = tokenprovider.generateJwtToken(dto);
flag = true; //로그인 성공 실패 flag 값
map.put("token", token);
}
map.put("flag", flag);
return map;
}
// 검색 (로그인 완료 후 로그인 한 사람의 정보를 꺼내는 url)
@PostMapping("/token")
public Map getByToken(String token) {
boolean flag = true;
Map map = new HashMap();
try {
//받은 토큰에서 로그인한 사람의 아이디, 타입 정보를 추출
String id = tokenprovider.getUsernameFromToken(token);
int type = tokenprovider.getRoleFromToken(token);
map.put("id", id);
map.put("type", type);
} catch (Exception e) {
flag = false;
}
map.put("flag", flag);
return map;
}
// 검색 (로그인 완료 후 로그인 한 사람의 정보를 꺼내는 url)
@GetMapping("")
public Map getInfo(@RequestHeader("token") String token) {
boolean flag = true;
Map map = new HashMap();
try {
String id = tokenprovider.getUsernameFromToken(token);
int type = tokenprovider.getRoleFromToken(token);
map.put("id", id);
map.put("type", type);
} catch (Exception e) {
flag = false;
}
map.put("flag", flag);
return map;
}
postman 에서 아래와 같이 테스트한다
html 파일 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#btn').click(function(){
let id = $('#id').val();
$.ajax({
url:'http://localhost:8083/members/login',
type:'post',
dataType:'json',
data:{'id':$('#id').val(), 'pwd':$('#pwd').val()},
success:function(result){
if(result.flag){
sessionStorage.setItem("token", result.token);
location.href="../index2.html";
}else{
alert('로그인 실패');
}
},
error:function(req, status){//req:요청객체, status:상태값
alert(status);
}
});
});
});
</script>
</head>
<body>
<h3>로그인폼</h3>
id:<input type="text" id="id"><br/>
pwd:<input type="text" id="pwd"><br/>
<input type="button" value="login" id="btn">
</body>
</html>
로그인 성공하면 이동하는 페이지 index2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
let token = sessionStorage.getItem("token");
$('#token').text(token);
$.ajax({
url:'http://localhost:8083/members',
type:'get',
dataType:'json',
headers:{'token':token},
success:function(result){
if(result.flag){
alert(result.id + " / " + result.type);
}else{
alert('인증 실패');
}
},
error:function(req, status){//req:요청객체, status:상태값
alert(status);
}
});
});
</script>
</head>
<body>
token:<span id="token"></span><br/>
</body>
</html>
반응형