작성
·
472
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
답변 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
다시 올렸습니다