// 회원탈퇴, 비밀번호 변경, 회원정보 수정 ... 로그인이 되어야 되는 모든 것.
// 회원정보수정 => 토큰을 주세요. 검증해서 성공하면 정보수정을 진행
@PostMapping(value="/update.json")
public Map<String, Object> updatePOST(@RequestHeader(name = "token") String token) {
Map<String, Object> retMap = new HashMap<>();
try {
// 1. 토큰을 받아서 출력
log.info("{}", token);
// 2. 실패시 전달값
retMap.put( "status", 0 );
// 3. 토큰을 검증 후 성공
if ( jwtUtil2.checkJwt(token) == true) {
// 4. 정보를 수정함.
retMap.put( "status", 200 );
}
} catch (Exception e) {
e.printStackTrace();
retMap.put( "status", -1 );
retMap.put( "error", e.getMessage() );
}
return retMap;
}
어제 생성하였던 update.json을 사용해보자.
// 토큰에 대해서 검증하고 데이터를 추출하는 메소드
public Student2 checkJwt(String token) throws Exception{
try {
// 1. key 준비
byte[] keyBytes = DatatypeConverter.parseBase64Binary(BASEKEY);
Claims claims = Jwts.parserBuilder()
.setSigningKey(keyBytes)
.build()
.parseClaimsJws(token)
.getBody();
Student2 obj = new Student2();
obj.setEmail( (String)claims.get("id") );
obj.setName((String) claims.get("name"));
return obj;
}
catch(ExpiredJwtException e1) {
System.err.println("만료시간 종료" + e1.getMessage());
return null;
}
catch(JwtException e2) {
System.err.println("토큰오류" + e2.getMessage());
return null;
}
catch(Exception e) {
System.out.println("e1과 e2 오류 아닌 모든 오류" + e.getMessage());
return null;
}
}
JwtUtil2.java를 위처럼 수정한다.
로그인을 하여 토큰을 받고
이렇게 이름과 전화번호를 변경하면
db에도 변한 것을 확인할 수 있다.
@ComponentScan(basePackages = { "com.example.controller", "com.example.service", "com.example.config",
"com.example.restcontroller", "com.example.controller.jpa","com.example.controller.mybatis", "com.example.filter" }) // 컨트롤러, 서비스 위치, 시큐리티 환경설정
20230427Application.java에서 filter 위치를 추가한다.
// 회원정보수정, 회원탈퇴, 비번번경 토큰이 필요한 경우에 대한 처리
// 컨트롤러 전에 수행되는 클래스 => 토큰의 유효성을 검증하고 실패 시 컨트롤러 진입X
// url 주소에 따라 분류함
@Component
@RequiredArgsConstructor
public class JwtFilter2 extends OncePerRequestFilter{
final JwtUtil2 jwtUtil2;
ObjectMapper objectMapper = new ObjectMapper(); // json으로 변환하는 라이브러리
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{
try{
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");;
Map<String, Object> retMap = new HashMap<>();
String token = request.getHeader("token");
if(token == null){ // {status:-1, message:"token null"}로 반환됨
retMap.put("status", -1);
retMap.put("message", "token null");
String result = objectMapper.writeValueAsString(retMap);
response.getWriter().write(result);
return; // 메소드 종료
}
if( token.length() <= 0 ){ // {status:-1, message:"token is empty"}로 반환됨.
retMap.put("status", -1);
retMap.put("message", "token is empty");
String result = objectMapper.writeValueAsString(retMap);
response.getWriter().write(result);
return; // 메소드 종료
}
Student2 obj = jwtUtil2.checkJwt(token);
if( obj == null ){
retMap.put("status", -1);
retMap.put("message", "token error");
String result = objectMapper.writeValueAsString(retMap);
response.getWriter().write(result);
return; // 메소드 종료
}
// 아래 명령어가 실행되어가 정상적인 컨트롤러로 진입 가능.
filterChain.doFilter(request, response);
}
catch (Exception e){
e.printStackTrace();
response.sendError(-1, "token error");
}
}
}
example 아래에 filter 폴더를 생성하여 JwtFilter2.java를 생성한다.
@Configuration
@Slf4j
public class FilterConfig {
@Bean // 서버가 구동될 때 자동으로 호출됨
// JwtFilter2 필터가 적용되는 url을 설정
public FilterRegistrationBean<JwtFilter2> filterRegistrationBean(JwtFilter2 jwtFilter){
log.info("filter => {}", "filterConfig");
FilterRegistrationBean<JwtFilter2> filterReg = new FilterRegistrationBean<>();
filterReg.setFilter(jwtFilter);
filterReg.addUrlPatterns("/api/student2/update.json");
filterReg.addUrlPatterns("/api/student2/delete.json");
// filterReg.addUrlPatterns("/api/student2/*"); // *는 전체url
return filterReg;
}
}
config 폴더에 FilterConfig.java를 생성한다.
token을 비웠을 때
token 값이 틀렸을 때
token 값이 일치할 때
// 로그인 후에 이전페이지로 되돌아 가기 위헤서 현재의 페이지를 저장하는 필터
// 현재페이지 중에서 로그인, 로그아웃은 제외시킴
@Slf4j
@Component
@RequiredArgsConstructor
public class UrlFilter extends OncePerRequestFilter{@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try{
// ex) /ROOT/api/student2/update.json?id=a
String contextPath = request.getContextPath(); // /ROOT
String path = request.getServletPath(); // /api/student2/update.json
String query = request.getQueryString(); // id=a
log.info("{},{},{}", contextPath, path, query);
// url에 login, logout이 포함되지 않은 경우..
if( !path.contains("login") && !path.contains("logout")){
HttpSession httpSession = request.getSession();
if(query == null){
httpSession.setAttribute("url", path);
}
else {
httpSession.setAttribute("url", path + "?" + query);
}
}
filterChain.doFilter(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
filter 폴더에 UrlFilter.java를 생성한다.
@Bean // 서버가 구동될 때 자동으로 호출됨
// JwtFilter2 필터가 적용되는 url을 설정
public FilterRegistrationBean<JwtFilter2> filterRegistrationBean(JwtFilter2 jwtFilter){
log.info("filter => {}", "filterConfig");
...
@Bean // 서버가 구동될 때 자동으로 호출됨
public FilterRegistrationBean<UrlFilter> filterRegistrationBean(UrlFilter urlFilter){
log.info("filter => {}", "filterConfig");
FilterRegistrationBean<UrlFilter> filterReg = new FilterRegistrationBean1<>();
filterReg.setFilter(urlFilter);
filterReg.addUrlPatterns("/api/student2/*"); // *는 전체url
return filterReg;
}
FilterConfig.java에 위 코드를 추가한다.
@GetMapping(value="/my/login.do")
public String mylogin(){
return "/student2/mylogin";
}
@PostMapping(value="myloginaction.do")
public String myloginAction(@ModelAttribute Student2 obj) {
try{
log.info("{}", obj.toString());
// DetailsService를 사용하지 않고 세션에 저장하기
// 1. 기존 자료 읽기
Student2 obj1 = s2Repository.findById(obj.getEmail()).orElse(null);
// 2. 전달한 아이디와 읽은 데이터 암호 비교
if( bcpe.matches(obj.getPassword(), obj1.getPassword()) ) {
// 3. 세션에 저장할 객체 생성하기 (저장할 객체, null, 권한)
String[] strRole = {"ROLE_STUDENT2"};
Collection<GrantedAuthority> role = AuthorityUtils.createAuthorityList(strRole);
User user = new User( obj.getEmail(), obj1.getPassword(), role); //
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null);
// 수동으로 세션에 저장
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authenticationToken);
SecurityContextHolder.setContext(context);
}
return "redirect:/student2/home.do";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
Student2Controller.java에 위 코드를 추가한다.
로그인이 정상적으로 실행된다.