Inflearn Community Q&A
RSA 검증 기능 구현 - PublicKey.txt 에 의한 검증 46:20
Written on
·
606
0
/api/user get 요청시
JwtAuthorizationRsaPublicKeyFilter#doFilterInternal
코드를 블록에서 에러가 발생합니다.
Jwt jwt = jwtDecoder.decode(getToken(request));
String username = jwt.getClaimAsString("username");디버깅으로 따라가봤습니다.
JwtAuthenticationFilter#getToken 리턴값으로
(토큰값에서 Bearer를 없애고 리턴한 값)
Jwt jwt = jwtDecoder.decode(getToken(request));위 코드를 실행했었어야 했는데 자꾸 프로그램이 종료가 됩니다?
원인을 알 수 가없습니다.


깃 클론 링크입니다.
git@github.com:InSuChoe/spring-security-oauth2.git
Quiz
What were the main validation methods for JWT tokens covered in the lecture?
MAC, RSA, Keytool
MAC, RSA, JWKSetUri
Filter, Decoder, Provider
Symmetric key, Asymmetric key, Digital signature
Answer 3
0
네
깃헙에 올려주신 소스와 해당 강의 챕터에서 제공하는 강의의 소스와 일부 다른 부분이 있어 정확한 테스트가 어려운 점이 있습니다.
정확한 원인을 발견하기 위해서 가급적 소스를 바로 실행할 수 있는 상태로 올려 주시기 부탁드립니다.
일단 제가 소스를 원 상태로 정리한 후에 실행한 결과입니다.
오류는 발생하지 않았습니다.
다만 모든 검증이 완료되고 인증완료 후 IndexController 의 /api/user 로 가게 되는데 인증객체타입이 맞지 않아서 오류가 나고 있습니다.
이 부분을 제외하면 정상적으로 동작하는 것 같습니다.
제가 정리한 소스를 참고해 주시기 바랍니다.
package io.security.oauth2.springsecurityoauth2.config;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.RSAKey;
import io.security.oauth2.springsecurityoauth2.filter.authentication.JwtAuthenticationFilter;
import io.security.oauth2.springsecurityoauth2.filter.authorization.JwtAuthorizationRsaPublicKeyFilter;
import io.security.oauth2.springsecurityoauth2.signature.RSAPublicKeySecuritySigner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
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.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class Oauth2ResourceServer {
/*@Bean
public SecurityFilterChain securityFilterChain1(HttpSecurity httpSecurity) throws Exception {
httpSecurity.antMatcher("/photos/1")
.authorizeRequests(req -> req.antMatchers("/photos/1")
.hasAuthority("SCOPE_photo")
.anyRequest().authenticated());
httpSecurity.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return httpSecurity.build();
}
@Bean
public SecurityFilterChain securityFilterChain2(HttpSecurity httpSecurity) throws Exception {
httpSecurity.antMatcher("/photos/2")
.authorizeRequests(req -> req.antMatchers("/photos/2")
.permitAll()
.anyRequest().authenticated());
httpSecurity.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return httpSecurity.build();
}*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable();
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.authorizeRequests(req -> req.antMatchers("/").permitAll()
.anyRequest().authenticated());
httpSecurity.userDetailsService(userDetailsService());
// httpSecurity.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
httpSecurity.addFilterBefore(jwtAuthenticationFilter(null, null), UsernamePasswordAuthenticationFilter.class);
httpSecurity.addFilterBefore(jwtAuthorizationRsaPublicKeyFilter(null),UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
@Bean public JwtAuthorizationRsaPublicKeyFilter jwtAuthorizationRsaPublicKeyFilter(JwtDecoder jwtDecoder) throws JOSEException {
return new JwtAuthorizationRsaPublicKeyFilter(jwtDecoder);
}
// @Bean
// public JwtAuthorizationRsaFilter jwtAuthorizationRsaFilter(RSAKey rsaKey) throws JOSEException {
// return new JwtAuthorizationRsaFilter(new RSASSAVerifier(rsaKey.toRSAPublicKey()));
// }
// @Bean
// public JwtAuthorizationMacFilter jwtAuthorizationMacFilter(OctetSequenceKey octetSequenceKey) throws JOSEException {
// return new JwtAuthorizationMacFilter(new MACVerifier(octetSequenceKey.toSecretKey()));
// }
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(RSAPublicKeySecuritySigner rsaPublicSecuritySigner, RSAKey rsaKey) throws Exception {
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(rsaPublicSecuritySigner, rsaKey);
jwtAuthenticationFilter.setAuthenticationManager(authenticationManager(null));
return jwtAuthenticationFilter;
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("user")
.password("1234")
.authorities("ROLE_USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
application.yml
server:
port: 8081
spring:
security:
oauth2:
resourceserver:
jwt:
# jwk-set-uri: http://localhost:8080/realms/oauth2/protocol/openid-connect/certs
# jws-algorithms: RS256
public-key-location: classpath:certs/publicKey.txt
main:
allow-bean-definition-overriding: true인증이 완료되면 UsernamePasswordAuthenticationToken 타입으로 인증객체가 생성됩니다.
JwtAuthenticationToken 은 시큐리티의 내장 필터인 BearerTokenAuthenticationFilter 사용했을 때 검증 이후 생성되는 객체입니다.
해당 강의 소스에서는 JwtAuthorizationRsaPublicKeyFilter 에서 검증처리 및 인증객체를 생성 하고 있습니다.
package io.security.oauth2.springsecurityoauth2.controller;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.net.URISyntaxException;
@RestController
public class IndexController {
@GetMapping("/index")
public String index(Authentication authentication){
return "index";
}
@GetMapping("/api/user")
public Authentication apiUser(Authentication authentication, @AuthenticationPrincipal Jwt principal) throws URISyntaxException {
if(authentication instanceof JwtAuthenticationToken) {
JwtAuthenticationToken authenticationToken = (JwtAuthenticationToken) authentication;
String sub = (String) authenticationToken.getTokenAttributes().get("sub");
String email = (String) authenticationToken.getTokenAttributes().get("email");
String scope = (String) authenticationToken.getTokenAttributes().get("scope");
String sub1 = principal.getClaim("sub");
String token = principal.getTokenValue();
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "Bearer " + token);
RequestEntity<String> reqest = new RequestEntity<>(httpHeaders, HttpMethod.GET, new URI("http://localhost:8082"));
// ResponseEntity<String> response = restTemplate.exchange(reqest, String.class);
// String body = response.getBody();
}
return authentication;
}
}
0
0






다시 올렸습니다