작성
·
1.6K
0
https://github.com/bgseong/Security-test
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private TokenService tokenService;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, TokenService tokenService) {
super(authenticationManager);
this.tokenService = tokenService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
super.doFilterInternal(request, response, chain);
String token = tokenService.resolveToken(request);
if(token == null){
chain.doFilter(request, response);
return;
}
if (tokenService.validateToken(token)) {
Authentication authentication = tokenService.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
System.out.println(SecurityContextHolder.getContext().getAuthentication());
}
chain.doFilter(request,response);
}
}
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Autowired
TokenService tokenService;
@Autowired
CorsConfig corsConfig;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.csrf().disable()
.httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin().disable()
.apply(new MyCustomDsl())
.and()
.authorizeHttpRequests(authorize ->
authorize
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // 특정 정적 리소스 허용
.requestMatchers("/api/v1/user/**").hasAnyRole("ADMIN", "MANAGER")
.requestMatchers("/api/v1/manager/**").hasRole("ADMIN")
.requestMatchers("/api/v1/admin/**").hasRole("ROLE_ADMIN")
.anyRequest().permitAll());
return http.build();
}
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
@Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
http
.addFilter(corsConfig.corsFilter())
.addFilter(new LoginFilter(authenticationManager,tokenService))
.addFilter(new JwtAuthorizationFilter(authenticationManager,tokenService));
}
}
}
@Component
public class TokenService implements InitializingBean {
private final UserRepository usersrepository;
private final Logger logger = LoggerFactory.getLogger(TokenService.class);
private static final String AUTHORITIES_KEY = "auth";
private final String secret;
private final long accessTokenValidityInMilliseconds;
private final long refreshTokenValidityInMilliseconds;
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String REFRESHTOKEN_HEADER = "RefreshToken";
private Key key;
public TokenService(
UserRepository usersrepository, @Value("${spring.jwt.secret}") String secret,
@Value("${spring.jwt.token-validity-in-seconds}") long tokenValidityInSeconds) {
this.usersrepository = usersrepository;
this.secret = secret;
this.accessTokenValidityInMilliseconds = tokenValidityInSeconds * 500;
this.refreshTokenValidityInMilliseconds = tokenValidityInSeconds * 1000 * 336;
}
@Override
public void afterPropertiesSet() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
public String createAccessToken(PrincipalDetails principalDetails) {
return createAccessToken(principalDetails.getUser().getEmail(), principalDetails.getAuthorities());
}
public String createRefreshToken(PrincipalDetails principalDetails) {
return createRefreshToken(principalDetails.getUser().getEmail(), principalDetails.getAuthorities());
}
public String createAccessToken(String email, Collection<? extends GrantedAuthority> inputAuthorities) {
String authorities = inputAuthorities.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
long now = (new Date()).getTime();
String accessToken = Jwts.builder()
.setSubject(email)
.claim(AUTHORITIES_KEY, authorities)
.signWith(key, SignatureAlgorithm.HS512)
.setExpiration(new Date(now + this.accessTokenValidityInMilliseconds))
.compact();
return accessToken;
}
public String createRefreshToken(String email, Collection<? extends GrantedAuthority> inputAuthorities) {
String authorities = inputAuthorities.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
long now = (new Date()).getTime();
String Token = Jwts.builder()
.setSubject(email)
.claim(AUTHORITIES_KEY, authorities)
.signWith(key, SignatureAlgorithm.HS512)
.setExpiration(new Date(now + this.refreshTokenValidityInMilliseconds))
.compact();
return Token;
}
public Authentication getAuthentication(String token) {
Claims claims = Jwts
.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
User user = usersrepository.findByEmail(claims.get("sub",String.class));
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
PrincipalDetails principal = new PrincipalDetails(user);
return new UsernamePasswordAuthenticationToken(principal, null, authorities);
}
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
logger.info("worng JWT sign");
} catch (ExpiredJwtException e) {
logger.info("expire JWT");
} catch (UnsupportedJwtException e) {
logger.info("No support JWT");
} catch (IllegalArgumentException e) {
logger.info("JWT is worng");
}
return false;
}
}
이렇게 구성해 놨습니다. 그런데 모든 권한이 적용된 url에 접근을 하면 403 에러가 뜹니다.
필터에서 SecurityContextHolder를 출력하면 아래와 같이 출력이 되는 걸 확인했고
[Principal=com.securitytest.Securitytest.auth.PrincipalDetails@45095607, Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_ADMIN]]
컨트롤러에서 PrincipalDetails를 호출해보니, null이라서 오류가 난다고 뜹니다. 무엇이 문제일까요ㅠㅠ..
답변 2
0
코드를 보니 권한은 ADMIN 이라고 쓴 곳도 있고 ROLE_ADMIN 이라고 쓴 곳도 보이네요.
예를 들어 SecurityConfig
클래스 안에 SecurityFilterChain
를 보면,
권한 설정 하는 부분이 그러합니다. User.role 에 저장되는 권한 이름이 ADMIN 이라면 ADMIN, USER 등으로
권한을 설정하시고, ROLE_ADMIN, ROLE_USER 라면 이런 식으로 설정하시면 되겠습니다.
이 부분을 먼저 확인해보시겠어요 ?
0
안녕하세요, 인프런 AI 인턴이에요. 권한 인증 403 에러는 클라이언트가 요청한 리소스에 대한 접근 권한이 없을 때 발생하는 오류입니다.
403 에러가 발생하는 이유는 여러 가지가 있을 수 있는데요, 주로 다음과 같은 이유로 발생할 수 있습니다.
권한 설정 오류: 서버에서 요청한 리소스에 대한 접근 권한 설정이 제대로 이루어지지 않은 경우 403 에러가 발생할 수 있습니다. 해당 요청에 대한 접근 권한을 확인해보세요.
인증 토큰 오류: 인증 토큰이 올바르지 않거나 만료된 경우에도 403 에러가 발생할 수 있습니다. 토큰의 유효성을 확인하고, 만료되었다면 새로운 토큰을 발급받아 사용해보세요.
CORS(Cross-Origin Resource Sharing) 설정 오류: 다른 도메인에서 온 요청에 대해 서버가 허용하지 않는 경우에도 403 에러가 발생할 수 있습니다. CORS 설정을 확인해보세요.
또한, 이 외에도 다른 원인일 수 있으니 더 자세한 정보가 필요할 경우에는 로그를 확인하거나 디버깅을 통해 원인을 찾아보세요.
해당 코드를 보면 JwtAuthorizationFilter 클래스와 SecurityConfig 클래스가 있는데, 이 부분에서 권한 인증과 관련된 설정이 이루어지고 있을 것입니다. 관련 설정을 확인해보시고 오류를 해결해보세요.
더 자세한 도움이 필요하시다면, 코드의 다른 부분이나 로그 정보 등을 함께 공유해주시면 더 정확한 도움을 드릴 수 있을 거예요. 수고하세요!