토큰 발행을 위해서 restfull api를 개발해보자.
아래와 같이 gradle 환경을 구성했다.
...
id 'org.springframework.boot' version '2.6.7'
...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
// JWT(JSON Web Token)
implementation 'io.jsonwebtoken:jjwt:0.9.1'
}
...
application.yml
server:
port: 8083
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
password: [비밀번호]
url: jdbc:mariadb://localhost:3306/[db_name]?serverTimezone=Asia/Seoul&useSSL=false&characterEncoding=utf8
username: [유저네임]
hikari:
minimum-idle: 5
maximum-pool-size: 10
idle-timeout: 10000
connection-timeout: 10000
validation-timeout: 10000
max-lifetime: 580000
thymeleaf:
prefix: classpath:templates/
suffix: .html
cache: false
mvc:
static-path-pattern: /static/**
resources:
add-mappings: true
static-locations: classpath:/static/
jpa:
generate-ddl: true
database: MYSQL
properties:
hibernate:
dialect: org.hibernate.dialect.MariaDBDialect
ddl-auto: update
jdbc:
lob:
non_contextual_creation: true
show_sql: true
defer-datasource-initialization: true
messages:
basename: i18n/messages
encoding: UTF-8
jwt:
header: Authorization
access-secret: [base64로 변경된 문자]
access-token-validity-time: 3600 #1시간
refresh-secret: [base64로 변경된 문자]
refresh-token-validity-time: 86400 #24시간
...
@RequiredArgsConstructor
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger logger = LogManager.getLogger(SecurityConfig.class);
@Autowired
TokenProvider jwtTokenProvider;
@Autowired
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**","/images/**","/error","favicon.ico","/i18n/**");
web.httpFirewall(defaultHttpFirewall());
}
@Bean
public HttpFirewall defaultHttpFirewall() {
return new DefaultHttpFirewall();
}
@Bean
public PasswordEncoder passwordEncoder() {
/*커스터마이징*/
String idForEncode = "bcrypt";
Map encoders = new HashMap();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());
return new DelegatingPasswordEncoder("sha256", encoders);
//return PasswordEncoderFactories.createDelegatingPasswordEncoder();
//return new MessageDigestPasswordEncoder("SHA-256"); deprecated
//return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// token을 사용하는 방식이기 때문에 csrf를 disable합니다.
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
// enable h2-console
.and()
.headers()
.frameOptions()
.sameOrigin()
// 세션을 사용하지 않기 때문에 STATELESS로 설정
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
//로그인 api는 토큰이 없는 상태로 요청이 오기 때문에 허용
//회원가입 api는 토큰이 없는 상태로 요청이 오기 때문에 허용
.antMatchers([허용 url]).permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutUrl([로그아웃 url])
.logoutSuccessUrl([로그인 url])
.addLogoutHandler(new CustomLogoutHandler()) // 로그아웃 핸들러
//.logoutSuccessHandler(logoutSuccessHandler())
.and()
// JwtAuthenticationFilter를 UsernamePasswordAuthenticationFilter 전에 넣는다
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class)
;
}
}
//해당 클래스는 JwtTokenProvider가 검증을 끝낸 Jwt로부터 유저 정보를 조회해와서 UserPasswordAuthenticationFilter 로 전달합니다.
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends GenericFilterBean {
private final TokenProvider jwtTokenProvider;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 헤더에서 JWT 를 받아옵니다.
String token = jwtTokenProvider.resolveToken((HttpServletRequest) request);
// 유효한 토큰인지 확인합니다.
if (token != null && jwtTokenProvider.validateToken(token)) {
// 토큰이 유효하면 토큰으로부터 유저 정보를 받아옵니다.
Authentication authentication = jwtTokenProvider.getAuthentication(token);
// SecurityContext 에 Authentication 객체를 저장합니다.
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
/*토큰의 생성, 토큰의 유효성 검증 담당 */
@Component
public class TokenProvider {
private final Logger logger = LoggerFactory.getLogger(TokenProvider.class);
private final String accessSecret;
private final long accessTokenValidityTime;
private final String refreshSecret;
private long refreshTokenValidityTime;
private final CustomUserDetailService customUserDetailService;
// @PostConstruct
// protected void init() {
// secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
// }
public TokenProvider(
@Value("${jwt.access-secret}") String accessSecret
, @Value("${jwt.access-token-validity-time}") long accessTokenValidityTime
, @Value("${jwt.refresh-secret}") String refreshSecret
, @Value("${jwt.refresh-token-validity-time}") long refreshTokenValidityTime
, CustomUserDetailService customUserDetailService
) {
this.accessSecret = accessSecret;
this.accessTokenValidityTime = accessTokenValidityTime * 1000;
this.refreshSecret = refreshSecret;
this.refreshTokenValidityTime = refreshTokenValidityTime * 1000;
this.customUserDetailService = customUserDetailService;
}
/**
* authentication 파라미터를 받고 권한 설정해서
* 토큰 리턴
* @param userPk
* @param roles
* @return
*/
public TokenDto createToken(String userPk, List<String> roles) {
Claims claims = Jwts.claims().setSubject(userPk); // JWT payload 에 저장되는 정보단위, 보통 여기서 user를 식별하는 값을 넣는다.
//yml에서 설정한 토큰 시간 설정
Date now = new Date();
String accessToken = Jwts.builder()
.setClaims(claims) // 정보 저장
.setIssuedAt(now) // 토큰 발행 시간 정보
.setExpiration(new Date(now.getTime() + accessTokenValidityTime)) // set Expire Time
.signWith(SignatureAlgorithm.HS256, accessSecret) // 사용할 암호화 알고리즘과
// signature 에 들어갈 secret값 세팅
.compact();
//Refresh Token
String refreshToken = Jwts.builder()
.setClaims(claims) // 정보 저장
.setIssuedAt(now) // 토큰 발행 시간 정보
.setExpiration(new Date(now.getTime() + refreshTokenValidityTime)) // set Expire Time
.signWith(SignatureAlgorithm.HS256, refreshSecret) // 사용할 암호화 알고리즘과
// signature 에 들어갈 secret값 세팅
.compact();
return TokenDto.builder().accessToken(accessToken).refreshToken(refreshToken).key(userPk).build();
}
// JWT 토큰에서 인증 정보 조회
public Authentication getAuthentication(String token) {
Member userDetails = customUserDetailService.loadUserByUsername(this.getUserPk(token));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
// 토큰에서 회원 정보 추출
public String getUserPk(String token) {
return Jwts.parser().setSigningKey(accessSecret).parseClaimsJws(token).getBody().getSubject();
}
// Request의 Header에서 token 값을 가져옵니다. "Authorization" : "TOKEN값'
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getParameter("access-token") != null ? request.getParameter("access-token") : request.getHeader(Constant.AUTHORIZATION_HEADER);
logger.debug(bearerToken);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
// 토큰의 유효성 + 만료일자 확인
public boolean validateToken(String jwtToken) {
logger.debug("jwtToken = " + jwtToken);
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(accessSecret).parseClaimsJws(jwtToken);
logger.debug("================"+claims.getBody().get("sub").toString());
return !claims.getBody().getExpiration().before(new Date());
} catch (Exception e) {
logger.debug("e = " + e);
return false;
}
}
public String userCheck(String jwtToken) {
Jws<Claims> claims = Jwts.parser().setSigningKey(accessSecret).parseClaimsJws(jwtToken);
logger.debug("================"+claims.getBody().get("sub").toString());
return claims.getBody().get("sub").toString();
}
public String validateRefreshToken(RefreshToken refreshTokenObj){
// refresh 객체에서 refreshToken 추출
String refreshToken = refreshTokenObj.getRefreshToken();
try {
// 검증
Jws<Claims> claims = Jwts.parser().setSigningKey(refreshSecret).parseClaimsJws(refreshToken);
//refresh 토큰의 만료시간이 지나지 않았을 경우, 새로운 access 토큰을 생성합니다.
if (!claims.getBody().getExpiration().before(new Date())) {
return recreationAccessToken(claims.getBody().get("sub").toString(), claims.getBody().get("roles"));
}
}catch (Exception e) {
//refresh 토큰이 만료되었을 경우, 로그인이 필요합니다.
return null;
}
return null;
}
public String recreationAccessToken(String userEmail, Object roles){
Claims claims = Jwts.claims().setSubject(userEmail); // JWT payload 에 저장되는 정보단위
claims.put("roles", roles); // 정보는 key / value 쌍으로 저장된다.
Date now = new Date();
//Access Token
return Jwts.builder()
.setClaims(claims) // 정보 저장
.setIssuedAt(now) // 토큰 발행 시간 정보
.setExpiration(new Date(now.getTime() + accessTokenValidityTime)) // set Expire Time
.signWith(SignatureAlgorithm.HS256, accessSecret) // 사용할 암호화 알고리즘과
// signature 에 들어갈 secret값 세팅
.compact();
}
public String createToken2(String email) {
Claims claims = Jwts.claims().setSubject(email); // JWT payload 에 저장되는 정보단위, 보통 여기서 user를 식별하는 값을 넣는다.
//yml에서 설정한 토큰 시간 설정
Date now = new Date();
return Jwts.builder()
.setClaims(claims) // 정보 저장
.setIssuedAt(now) // 토큰 발행 시간 정보
.setExpiration(new Date(now.getTime() + accessTokenValidityTime)) // set Expire Time
.signWith(SignatureAlgorithm.HS256, accessSecret) // 사용할 암호화 알고리즘과
// signature 에 들어갈 secret값 세팅
.compact();
}
}
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
//필요한 권한이 없이 접근하려 할때 403
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
//유효한 자격증명을 제공하지 않고 접근하려 할때 401에러를 리턴할 클래스
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
// 유효한 자격증명을 제공하지 않고 접근하려 할때 401
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
@Builder
@Entity
@Getter
@Table(name = "T_REFRESH_TOKEN")
@NoArgsConstructor
@AllArgsConstructor
public class RefreshToken {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
private Long refreshTokenId;
@Column(nullable = false)
private String refreshToken;
@Column(nullable = false)
private String keyEmail;
@Column(nullable = false)
private String userAgent;
}
@ToString
@Getter
@Setter
@AllArgsConstructor
@Entity
@NoArgsConstructor
public class Member extends BaseTimeEntity implements UserDetails {
...
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
@Service
public class CustomUserDetailService implements UserDetailsService {
@Autowired
MemberRepository memberRepository;
@Override
public Member loadUserByUsername(String username) throws UsernameNotFoundException {
return memberRepository.findOneWithAuthoritiesById(username)
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다."));
}
}
@Service
@RequiredArgsConstructor
public class JwtService {
private static final Logger logger = LogManager.getLogger(JwtService.class);
private final TokenProvider jwtTokenProvider;
private final RefreshTokenRepository refreshTokenRepository;
@Transactional
public void login(TokenDto tokenDto, String userAgent){
RefreshToken refreshToken = RefreshToken
.builder()
.keyEmail(tokenDto.getKey())
.refreshToken(tokenDto.getRefreshToken())
.userAgent(userAgent)
.build();
String loginUserEmail = refreshToken.getKeyEmail();
if(refreshTokenRepository.existsByKeyEmailAndUserAgent(loginUserEmail, userAgent)){
logger.debug("기존의 존재하는 refresh 토큰 삭제");
refreshTokenRepository.deleteByKeyEmailAndUserAgent(loginUserEmail, userAgent);
}
refreshTokenRepository.save(refreshToken);
}
public Optional<RefreshToken> getRefreshToken(String refreshToken){
return refreshTokenRepository.findByRefreshToken(refreshToken);
}
public Map<String, String> validateRefreshToken(String refreshToken){
RefreshToken refreshToken1 = getRefreshToken(refreshToken).get();
String createdAccessToken = jwtTokenProvider.validateRefreshToken(refreshToken1);
return createRefreshJson(createdAccessToken);
}
public Map<String, String> createRefreshJson(String createdAccessToken){
Map<String, String> map = new HashMap<>();
if(createdAccessToken == null){
map.put("errortype", "Forbidden");
map.put("status", "402");
map.put("message", "Refresh 토큰이 만료되었습니다. 로그인이 필요합니다.");
return map;
}
//기존에 존재하는 accessToken 제거
map.put("status", "200");
map.put("message", "Refresh 토큰을 통한 Access Token 생성이 완료되었습니다.");
map.put("accessToken", createdAccessToken);
return map;
}
}
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LoginDto {
@NotNull
@Size(min = 3, max = 50)
private String email;
@NotNull
@Size(min = 3, max = 50)
private String pwd;
@NotNull
@Size(min = 3, max = 50)
private String site;
}
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ResponseDto<T1, T2, T3> {
private String error;
private List<T1> data;
private Map<T2,T3> map;
private String url;
private String msg;
private String code;
}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TokenDto {
private String grantType;
private String accessToken;
private String refreshToken;
private String key;
}
@CrossOrigin("*")
@RequestMapping("/api")
@RestController
@RequiredArgsConstructor
public class AuthController {
@Autowired
HttpSession httpSession;
private static final Logger logger = LogManager.getLogger(AuthController.class);
private final TokenProvider jwtTokenProvider;
private final CustomUserDetailService customUserDetailService;
private final JwtService jwtService;
// 로그인
/**
* 로그인
* 토큰 첫 발행
* https://backtony.github.io/spring/2021-07-12-spring-basic-8/
* https://recordsoflife.tistory.com/360
* @param userAgent
* @param loginDto
* @return
*/
@PostMapping("/login")
public ResponseEntity<ResponseDto> login(
HttpServletRequest request
, @RequestHeader("User-Agent") String userAgent
,@Valid @RequestBody LoginDto loginDto) {
String email = loginDto.getEmail();
String pwd = loginDto.getPwd();
String url = loginDto.getSite();
logger.debug("user email = {"+ email +"}");
Member member = customUserDetailService.loadUserByUsername(email);
TokenDto tokenDto = null;
Map<String,Object>map = new HashMap<>();
if (Objects.equals( member.getPwd(), CommonUtils.sha256(pwd) )) {
tokenDto = jwtTokenProvider.createToken(member.getId(), member.getRoles());
jwtService.login(tokenDto, userAgent);
map.put("info",tokenDto);
map.put("user",member);
} else {
return ResponseEntity.ok(ResponseDto.<String, String, Object>builder().code("0003").build());
}
return ResponseEntity.ok(ResponseDto.<String, String, Object>builder().code("0000").map(map).build());
}
/**
* 로그인
* 토큰 첫 발행
* https://backtony.github.io/spring/2021-07-12-spring-basic-8/
* https://recordsoflife.tistory.com/360
* @param loginDto
* @return
*/
@PostMapping("/login2")
public ResponseEntity<ResponseDto> login(
HttpServletRequest request
,@Valid @RequestBody LoginDto loginDto) {
String email = loginDto.getEmail();
String pwd = loginDto.getPwd();
String url = loginDto.getSite();
logger.debug("user email = {"+ email +"}");
Member member = customUserDetailService.loadUserByUsername(email);
TokenDto tokenDto = null;
Map<String,Object>map = new HashMap<>();
if (pwd != null && Objects.equals( member.getPwd(), CommonUtils.sha256(pwd) )) {
tokenDto = jwtTokenProvider.createToken(member.getId(), member.getRoles());
String userAgent = "111";
jwtService.login(tokenDto, userAgent);
map.put("info",tokenDto);
map.put("user",member);
} else {
throw new InputMismatchException("잘못된 비밀번호 입력");
}
return ResponseEntity.ok(ResponseDto.<String, String, Object>builder().url(Constant.URLMAP.get(url)).map(map).error(null).build());
}
/**
* 토큰 확인
* @param request
* @param userAgent
* @return
*/
@PostMapping("/access-token")
public ResponseEntity<ResponseDto> access_token(
HttpServletRequest request
, @RequestHeader("User-Agent") String userAgent) {
String accessToken = jwtTokenProvider.resolveToken(request);
logger.debug(accessToken);
boolean validAccessToken = jwtTokenProvider.validateToken(accessToken);
ResponseDto<String,String,String>dto;
if ( validAccessToken ) {
//TODO
//session 추가
dto = ResponseDto.<String, String, String>builder().code("0000").build();
} else {
dto = ResponseDto.<String, String, String>builder().msg("토큰 만료").code("0001").build();
}
logger.debug(userAgent);
return ResponseEntity.ok(dto);
}
/**
* 로그인 확인
* @param request
* @param userAgent
* @return
*/
@PostMapping("/check-login")
public ResponseEntity<ResponseDto> check_login(
HttpServletRequest request
, HttpSession httpSession
, @RequestHeader("User-Agent") String userAgent
) {
String accessToken = jwtTokenProvider.resolveToken(request);
logger.debug(accessToken);
boolean validAccessToken = jwtTokenProvider.validateToken(accessToken);
ResponseDto<String,String,String>dto;
if ( validAccessToken ) {
String userCheck = jwtTokenProvider.userCheck(accessToken);
logger.debug("userCheck = " + userCheck);
dto = ResponseDto.<String, String, String>builder().msg("유효한 토큰").build();
} else {
dto = ResponseDto.<String, String, String>builder().msg("만료된 토큰").build();
}
logger.debug(userAgent);
return ResponseEntity.ok(dto);
}
/**
* 토큰 재발행
* @param request
* @param params
* @param userAgent
* @return
*/
@PostMapping("/refresh")
public ResponseEntity<ResponseDto> refresh(
HttpServletRequest request
, @RequestBody Map<String, String> params
, @RequestHeader("User-Agent") String userAgent) {
String refreshToken = params.get("refreshToken");
if (refreshToken == null) {
return ResponseEntity.ok(ResponseDto.<String, String, Object>builder().code("0002").msg("토큰 없음").build());
} else {
RefreshToken refreshToken1 = jwtService.getRefreshToken(refreshToken).orElse(null);
if (refreshToken1 != null) {
String newAccessToken = jwtTokenProvider.validateRefreshToken(refreshToken1);
logger.debug(newAccessToken);
Map<String,Object>map = new HashMap<>();
if (newAccessToken != null) {
boolean validAccessToken = jwtTokenProvider.validateToken(newAccessToken);
if ( validAccessToken ) {
TokenDto tokenDto = TokenDto.builder().refreshToken(refreshToken).accessToken(newAccessToken).key(refreshToken1.getKeyEmail()).build();
map.put("info",tokenDto);
}
}
logger.debug(userAgent);
return ResponseEntity.ok(ResponseDto.<String, String, Object>builder().map(map).code("0000").build());
} else {
return ResponseEntity.ok(ResponseDto.<String, String, Object>builder().code("0001").msg("토큰 만료").build());
}
}
}
@GetMapping("/logout")
public ResponseEntity<?> logout () {
return ResponseEntity.ok("");
}
@PostMapping("/join")
public ResponseEntity<?> join () {
return ResponseEntity.ok("");
}
@PostMapping("/check-email")
public ResponseEntity<?> check_email (@RequestBody String email) {
logger.debug("email = " + email);
Member member = customUserDetailService.loadUserByUsername(email);
return ResponseEntity.ok(member);
}
}
class UserInfo {
constructor(email, pwd, site) {
this.email = email;
this.pwd = pwd;
this.site = site;
}
}
$(function (){
//로그인 버튼 이벤트
$('#loginButton').on('click',function(){
const iptId = $('#iptId');
const iptPassword = $('#iptPassword');
if ( iptId.val().length == 0 ) {
iptId.parent('div').siblings('.txt-error-1').css('display','');
return;
}
if ( iptPassword.val().length == 0 ) {
iptPassword.parent('div').siblings('.txt-error-1').css('display','');
return;
}
$('form')[0].submit();
// login();
});
})
//로그인
const login = async() => {
const id = document.getElementById('iptId').value;
const pwd = document.getElementById('iptPassword').value;
let user = new UserInfo(id, pwd, [site name]);
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(user)
}).then((res)=> {
return res;})
.catch((error) =>{
console.error(`submit data Error = [${error}]`);
});
console.log(response.ok);
if (response.ok) {
const data = await response.json();
console.log({data});
const accessToken = data.map.info.accessToken;
const refreshToken = data.map.info.refreshToken;
console.log(accessToken)
console.log(refreshToken)
window.localStorage.setItem('access-token', accessToken);
window.localStorage.setItem('refresh-token', refreshToken);
//goToPage(data.url);
} else {
//TODO
//잘못 입력
}
}
const check_login = async() => {
const token = 'Bearer '+window.localStorage.getItem("access-token");
const response = await fetch('/api/check-login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
, 'Authorization' : token
}
}).then((res)=> {
return res;})
.catch((error) =>{
console.error(`submit data Error = [${error}]`);
});
const data = await response.json();
}
//커스터마이징 기본 메소드
const test = async() => {
const token = 'Bearer '+window.localStorage.getItem("access-token");
console.log(token);
const response = await fetch('/api/access-token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
, 'Authorization' : token
}
}).then((res)=> {
return res;})
.catch((error) =>{
console.error(`submit data Error = [${error}]`);
});
console.log(response);
const data = await response.json();
console.log (data);
}
//리프레시 토큰 재발행
const refresh = async() => {
const token = window.localStorage.getItem("refresh-token");
const user = {
"refreshToken" : token
};
console.log(token);
const response = await fetch('/api/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(user)
}).then((res)=> {
return res;})
.catch((error) =>{
console.error(`submit data Error = [${error}]`);
});
console.log(response);
if (response.ok) {
const data = await response.json();
console.log (data);
const accessToken = data.map.info.accessToken;
const refreshToken = data.map.info.refreshToken;
window.localStorage.setItem('access-token', accessToken);
window.localStorage.setItem('refresh-token', refreshToken);
}
}
//페이지 변경
const goToPage = (param) => {
console.log(param);
location.href=param;
}
function setCookie(name, value, expiredays){
var today = new Date();
console.log(today.getDate())
today.setDate(today.getDate() + expiredays); // 현재시간에 expiredays를 더함
document.cookie = name + '=' + escape(value) + '; expires=' + today.toGMTString();
}
function getCookie(name) {
var cookie = document.cookie;
if (document.cookie != "") {
var cookie_array = cookie.split("; ");
console.log(cookie_array)
for ( var index in cookie_array) {
var cookie_name = cookie_array[index].split("=");
if (cookie_name[0] == name) {
return cookie_name[1];
}
}
}
return;
}
이런식으로 구성했다.
localstorage에서 cookie 방식으로 변경했다.