私は、サーバー送信イベントをブラウザにプッシュするSseEmitterを呼び出すSpring Controllerメソッドを持っています。ブラウザから、SSE URLのEventSourceを作成するためのjavascriptがホームページから実行されます。ホームページ自体には、Spring Securityフォームベースの認証を使用して行われる認証が必要です。そのため、認証に成功すると、ログインページはホームページに送られます。ただし、認証オブジェクトは、サーバー送信イベント方式でnullです。間違ったSpring Securityの設定がこれを引き起こしていると理解していますが、修正方法はわかりません!Springセキュリティ認証オブジェクトがSpring SseEmitterのnullです
以下私は
@Configuration
@EnableWebMvcSecurity
public class UCFSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
@Qualifier("epUser")
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationSuccessHandler successHandler;
....
....
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/rest/**").authenticated()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.htm").failureUrl("/error.htm")
.loginProcessingUrl("/spring_sec_auth.htm")
.usernameParameter("username").passwordParameter("password").permitAll()
.successHandler(successHandler)
.and()
.logout()
//.logoutSuccessUrl("/login.htm?logout")
.invalidateHttpSession(true)
.and().csrf().disable();
}
....
....
}
を使用するセキュリティ設定で以下SSE方法はNPEをスロー
SecurityContextHolder.getContext().getAuthentication()
から認証対象を使用するUserActivityService
にuserActivityFeed()
を呼び出し!
@Controller
public class UserActivityController {
@Autowired
private UserActivityService userActivityService;
@RequestMapping("/userActivity")
public ResponseBodyEmitter activityFeed() {
final SseEmitter emitter = new SseEmitter();
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(() -> {
try {
emitter.send(userActivityService.userActivityFeed() , MediaType.TEXT_PLAIN);
Thread.sleep(UCFConstants.USR_ACTV_REFRESH_PERIOD);
} catch (Exception e) {
e.printStackTrace();
emitter.completeWithError(e);
return;
}
emitter.complete();
});
service.shutdown();
return emitter;
}
}
JavascriptのSSEのEventSourceオブジェクトを作成するための
<script type="text/javascript">
var source = new EventSource("/MyApp/rest/userActivity");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data
+ "<br>";
};
</script>
私のアプリケーションのweb.xml
<servlet-mapping>
<servlet-name>MyApp</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyApp</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
'SecurityContextHolder.getContext()はセッション内のリクエスト間で共有されませんか?私は、春のセキュリティ関連オブジェクト(認証、プリンシパルなど)がその後の制限付きURLへのリクエストで利用できない場合、単一のエントリポイント認証(例えばログインURL)のポイントを理解できません – wildthing81
春のドキュメント、https: /docs.spring.io/spring-security/site/docs/3.0.x/reference/technical-overview.html単一のセッションで同時要求を受け取るアプリケーションでは、同じSecurityContextインスタンスがスレッド間で共有されます。 ThreadLocalが使用されていても、各スレッドのHttpSessionから取得されるのは同じインスタンスです。これは、スレッドが実行されているコンテキストを一時的に変更したい場合に意味があります。 – wildthing81
docは実際に要求を処理するコンテナスレッドについて述べています。しかし、あなたの 'userActivityFeed()'メソッドは、それ自身のスレッドでexecutorサービスによって実行されています。このスレッドはSecurityContextについて何も知らない – Leffchik