Spring Boot Webサービスを開発し、アクセス管理にKeycloakを使用しています。 Webサイトは、一部のユーザーデータをデータベースに保存します。これらのデータをログインしているユーザーに接続しようとしています。
現時点では、ユーザー名をデータとともに保存しています。しかし、私はユーザー名の代わりにユーザーIDを保存するのが好きです。どうやってやるの?
私はこれによってSecurityContextを取得しようとします:
@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public KeycloakSecurityContext getKeycloakSecurityContext() {
return ((KeycloakPrincipal<KeycloakSecurityContext>) getRequest().getUserPrincipal()).getKeycloakSecurityContext();
}
しかし、エラーが発生します:
There was an unexpected error (type=Internal Server Error, status=500).
Error creating bean with name 'scopedTarget.getKeycloakSecurityContext'
defined in com.SiteApplication: Bean instantiation via factory method
failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [org.keycloak.KeycloakSecurityContext]: Factory method
'getKeycloakSecurityContext' threw exception; nested exception is
Java.lang.ClassCastException:
org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken
cannot be cast to org.keycloak.KeycloakPrincipal
これは正しい方法ですか?何が欠けている?
ありがとうございました!
私は上記よりもはるかに簡単な解決策を見つけました:
_ @GetMapping
public ResponseEntity getEndpoint(String someParam, HttpServletRequest request) {
KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
String userId = principal.getAccount().getKeycloakSecurityContext().getIdToken().getSubject();
//....do something
return new ResponseEntity(HttpStatus.OK);
}
_
上記の例外は、タイプがKeycloakAuthenticationToken
であるときにgetRequest().getUserPrincipal()
を_KeycloakPrincipal<KeycloakSecurityContext>
_にキャストしようとしているため、_((KeycloakAuthenticationToken) getRequest().getUserPrincipal())
_が機能すると思います。
私は私たちのコードで同様のことをしました。
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("Expecting a HTTP request");
}
RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
if (context == null) {
handleNoSecurityContext(request, response, chain);
return;
}
AccessToken accessToken = context.getToken();
Integer userId = Integer.parseInt(accessToken.getOtherClaims().get("user_id").toString());
chain.doFilter(request, response);
}
}
これを行う前に、keycloakによって発行されているアクセストークンにuser_id
を追加する必要があります。以下のスクリーンショットに示すように、マッパーを介してこれを行うことができます。
また、アプリケーションクラスに@Bean
メソッドを追加して、上記の処理フィルターをアプリケーションのライフサイクルに追加することを忘れないでください。
@Configuration
@EnableAutoConfiguration(exclude = {FallbackWebSecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class, DataSourceAutoConfiguration.class})
@ComponentScan
@EnableAsync
public class MyServiceClass {
public static void main(String[] args) {
Properties properties = new Properties();
new SpringApplicationBuilder(MyServiceClass.class)
.properties(properties)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
@Bean
public AuthenticationTokenProcessingFilter authFilter() {
return new AuthenticationTokenProcessingFilter();
}
}