我最近切换到Spring Security来处理我的Web应用程序的登录,注销和基于角色的访问。我使用flash消息来获取信息和错误消息,并希望在成功登录和注销后显示这样的消息。
在JSP文件中,使用以下代码显示这些消息:
<c:if test = "${not empty flashmessage_error}" >
<div class="alert alert-danger"><c:out value="${flashmessage_error}" />
</div>
</c:if>
<c:if test="${not empty flashmessage_info}" >
<div class="alert alert-info"><c:out value="${flashmessage_info}" />
</div>
</c:if>
要在成功登录后显示flash消息,我定义了一个自定义LoginSuccessHandler ,它将消息放入FlashMap并将重定向页面设置为主页:
public class FlashMessageAuthSuccessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
private String flashMessage = "Logged in!";
public void setFlashMessage(String flashMessage) {
this.flashMessage = flashMessage;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
FlashMapManager flashMapManager = new SessionFlashMapManager();
FlashMap fm = new FlashMap();
fm.put(KeyConstants.FLASH_INFO_KEY, flashMessage);
flashMapManager.saveOutputFlashMap(fm, request, response);
setDefaultTargetUrl("/");
super.onAuthenticationSuccess(request, response, authentication);
}
}
我的 SecurityConfig 类如下所示:
@Configuration
@EnableWebSecurity(debug = false)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private MessageSource messageSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
/*
* HttpSecurity allows configuring web based security for specific HTTP requests
* By default it will be applies to all request, but can be restricted
* using requestMatcher
* @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);
http
.authorizeRequests()
.antMatchers("/", "/css/**", "/js/**", "/images/**", "/about", "/error").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginPage("/login")
.loginProcessingUrl("/ssprocesslogin") //post request
// .defaultSuccessUrl("/") //cannot possibly used in combination with successHandler?
.successHandler(loginSuccesHandler())
.failureUrl("/login?" + KeyConstants.FLASH_ERROR_KEY + "=Verkeerde login message aanpassen") //default is /login?error
.permitAll()
.and()
.rememberMe()
.tokenValiditySeconds(2592000) //one month
.rememberMeParameter("j_rememberme")
.key("wIllekEUrigeSleutteL")
.userDetailsService(userDetailsService)
.and()
.logout()
.logoutUrl("/logout") //default is /logout
// .logoutSuccessUrl("/") //default is /login?logout
.logoutSuccessHandler(new FlashMessageLogoutSuccessHandler())
.invalidateHttpSession(true) //true is the default
;
}
@Bean
public FlashMessageAuthSuccessHandler loginSuccesHandler() {
FlashMessageAuthSuccessHandler handler = new FlashMessageAuthSuccessHandler();
//THIS DOES NOT WORK!!!!!
String loginSuccessMessage = messageSource.getMessage("flashmessage.loginsuccesful", null, "not found", null);
handler.setFlashMessage(loginSuccessMessage);
return handler;
}
@Bean
public AuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider dap = new DaoAuthenticationProvider();
dap.setUserDetailsService(userDetailsService);
dap.setPasswordEncoder(passwordEncoder());
return dap;
}
@Bean
public ShaPasswordEncoder passwordEncoder() {
return new ShaPasswordEncoder(256);
}
}
但是没有显示来自messages.properties文件的正确消息。相反,字符串&#34;未找到&#34;登录后显示为flash消息。 在下面的行中,我尝试使用注入的MessageSource通过消息键查找消息,但显然找不到它并显示回退消息:
String loginSuccessMessage = messageSource.getMessage("flashmessage.loginsuccesful", null, "not found", null);
messageSource bean在MvcConfig文件中定义,如下所示,用于在JSP文件中显示消息时工作正常,但似乎无法在Spring Security配置文件中自动装配以获取所需的flash消息。
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
我有什么想法可以做到这一点?
答案 0 :(得分:0)
您正在配置对象内自动装配消息源。 MessageSource bean很可能还没有准备好。
我会尝试这样的事情:
private void yourCharacterInformationButton_Click(object sender, RoutedEventArgs e)
{
if (AllFilesExist("NameData.xml", "ClassData.xml"))
{
// Omitted for brevity...
}
}
答案 1 :(得分:0)
在applicationContext.xml中,添加以下内容:
<util:properties id="message" location="classpath:com/your/program/resources/message.properties" />
或如果使用基于java的配置:
@Bean(name = "message")
public PropertiesFactoryBean message() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("com/your/program/resources/message.properties"));
return bean;
}
创建一个字段变量并在Security Config中使用@Value注释,如下所示:
@Value(value = "#{'${flashmessage.loginsuccesful}'}")
private String loginSuccessMessage;
或
@Value("#{message['flashmessage.loginsuccesful']}")
private String loginSuccessMessage;
检查link以供参考。
答案 2 :(得分:0)
我认为这确实是MessageSource未准备好在Configuration对象中注入的问题。您的解决方案可能会起作用,并涉及使用@Value注释从application.properties文件中读取属性。我已经在AppConfig类中读过这个文件了:
@Configuration
@PropertySource(value= {"classpath:application.properties"})
public class AppConfig {
}
并在注入Environment对象的其他配置文件中访问所需的值:
@Autowired
private Environment env;
并在loginSuccesHandler()方法中:
String loginSuccessMessage = env.getProperty("flashmessage.loginsuccesful");
这确实有效,部分解决了这个问题。剩下的问题是财产声明:
flashmessage.loginsuccesful=You have been logged in succesfully!
需要从messages.properties移动到application.properties,而我使用属性的主要原因是将其与其他本地化消息一起定义,将来可能使用不同的语言。 但也许这根本不可能,因为此时不知道区域设置?
<强>更新强> 我通过将MessageSource bean的声明从Dispatcher servlet上下文(MvcConfig.java)移动到Root上下文(AppConfig.java)来解决了这个问题。 SecurityConfig类显然无法访问servlet上下文。
答案 3 :(得分:0)
在具有spring-boot-starter-thymeleaf
依赖性的Spring Boot 2.3中对我有用的东西:
在我的@Configuration
班上:
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
@Bean
public MessageSourceAccessor getMessageSourceAccessor(MessageSource messageSource) {
return new MessageSourceAccessor(messageSource);
}
然后在我要动态访问messages.properties中的值的任何bean中:
@Autowired
MessageSourceAccessor messageSourceAccessor;
...
messageSourceAccessor.getMessage(key)