jwt, security, user

seonh0·2022년 4월 21일
0

springbootJpa

목록 보기
3/4

jwt

  • 토큰을 발행, 정보추출용으로 사용한다
  • 헤더, 페이로드, 시그니쳐로 이루어져 있다.

package com.example.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.example.jwt.JwtUtil;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.filter.OncePerRequestFilter;

@WebFilter(urlPatterns = { "/api/customer/mypage" })
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain)
            throws ServletException, IOException {
        try {
            // 토큰 가져오기
            String token = request.getHeader("TOKEN");
            if (token != null) {
                if (token.length() > 0) {
                    // 토큰을 이용해서 아이디 추출하기
                    String username = jwtUtil.extractUsername(token);
                    // 토큰 검증
                    System.out.println("jwtRequestFilter : " + token);
                    System.out.println("username : " + username);

                    // 컨트롤러로 이동
                    filterChain.doFilter(request, response);
                }

            }
            // 토큰 없으면 오류발생
            else {
                throw new Exception("토큰없음");
            }
        } catch (Exception e) {
            e.printStackTrace();
            response.sendError(-1, "토큰오류");
        }
    }

}

package com.example.jwt;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import org.springframework.stereotype.Service;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

// 토큰을 발행 및 정보추출용
@Service
public class JwtUtil {

    private final String SECURITY_KEY = "fjehje#$4343";

    // 1000 => 1초
    private final long VALIDATE_TIME = 1000 * 60 * 60 * 9; // 9H

    // 토큰 생성(아이디 정보)
    public String generatorToken(String username) {
        Map<String, Object> map = new HashMap<>();
        String token = Jwts.builder()
                .setClaims(map)
                .setSubject(username) // 토큰제목
                .setIssuedAt(new Date(System.currentTimeMillis())) // 토큰생성일
                .setExpiration(new Date(System.currentTimeMillis() + VALIDATE_TIME)) // 토큰유효시간
                .signWith(SignatureAlgorithm.HS256, SECURITY_KEY)
                .compact();

        return token;
    }

    // 정보 추출용 메소드
    private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = Jwts.parser().setSigningKey(SECURITY_KEY).parseClaimsJws(token).getBody();
        return claimsResolver.apply(claims);
    }

    // 토큰에서 아이디 추출
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    // 토큰에서 만료시간 추출
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    // 유효시간 체크
    public boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    // 토큰이 유효한지 체크
    public boolean isTokenValidation(String token, String uid) {
        String username = extractUsername(token);
        if (username.equals(uid) && isTokenExpired(token)) {
            return true;
        }
        return false;
    }

}

security

  • configuration을 통해서 접근권한을 설정한다.
  • UserDetailServiceImpl를 통해서 권한을 확인할 수 있도록 한다.
package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.example.service.UserDetailsServiceImpl;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

        // 1. 직접 만든 detailService 객체 가져오기
        @Autowired
        UserDetailsServiceImpl detailsService;

        // 회원가입시 암호화 했던 방법의 객체생성
        // 2. 암호화 방법 객체 생성, @Bean은 서버 구동시 자동으로 객체 생성됨
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
                return new BCryptPasswordEncoder();
        }

        // 3. 직접만든 detailsService에 암호화 방법 적용
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.userDetailsService(detailsService)
                                .passwordEncoder(bCryptPasswordEncoder());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                // super.configure(http);

                // 페이지별 접근 권한 설정
                http.authorizeRequests()
                                .antMatchers("/admin", "/admin/**")
                                .hasAuthority("ADMIN")
                                .antMatchers("/seller", "/seller/**")
                                .hasAnyAuthority("ADMIN", "SELLER")
                                .antMatchers("/customer", "/customer/**")
                                .hasAuthority("CUSTOMER")
                                .anyRequest().permitAll();

                // 로그인 페이지 설정, 단 POST는 직접 만들지 않음
                http.formLogin()
                                .loginPage("/member/login")
                                .loginProcessingUrl("/member/loginaction")
                                .usernameParameter("uemail")
                                .passwordParameter("upw")
                                .defaultSuccessUrl("/home")
                                .permitAll();

                // 로그아웃 페이지 설정, url에 맞게 POST로 호출하면 됨.
                http.logout()
                                .logoutUrl("/member/logout")
                                .logoutSuccessUrl("/home")
                                // .logoutSuccessHandler(new MyLogoutSuccessHandler())
                                .invalidateHttpSession(true)
                                .clearAuthentication(true)
                                .permitAll();

                // 접근권한불가 403
                http.exceptionHandling().accessDeniedPage("/page403");

                // h2-console을 사용하기 위해서
                http.csrf().ignoringAntMatchers("/h2-console/**");
                http.headers().frameOptions().sameOrigin();

                // rest controller 사용
                http.csrf().ignoringAntMatchers("/api/**");
        }

}

user

  • security의 filter와 같은 느낌이다.
  • user의 아이디를 통해서 데이터를 가져온다.
package com.example.service;

import java.util.Collection;

import com.example.dto.MemberDTO;
import com.example.mapper.MemberMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

// 로그인에서 버튼을 누르면 컨트롤을 통과해서 서비스로 이메일이 전달됨
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    MemberMapper mMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("UserDetails" + username);
        MemberDTO member = mMapper.memberEmail(username);

        String[] strRole = { member.getUrole() };

        Collection<GrantedAuthority> roles = AuthorityUtils.createAuthorityList(strRole);

        User user = new User(username, member.getUpw(), roles);
        return user;
    }

}
profile
1111

0개의 댓글