LocalContextHandler usage - spring

I am very new to LocalContexHandler. I have read about it. From what I understood it is used to retrieve locale information in a java application.
I am passing the locale from the url as follows:
url?lang = fr
When I am trying to retrieve the locale in java application as follows:
Locale locale = LocaleContextHolder.getLocale();
It is giving null value. Can someone help me understand it's usage or is there any other alternative for the same?

If you want to pass locale in URL you must register LocaleChangeInterceptor interceptor and create LocaleResolver bean. For example SessionLocaleResolver stores chosen locale in session. Then LocaleContextHolder#getLocale will return not-null value. Take a look in Spring documentation to section Using locales. Below you can see basic Java configuration for you example.
If you want just use LocaleContextHolder you have to call LocaleContextHolder#setLocale from your code before calling LocaleContextHolder#getLocale. It's just simple holder class that stores LocaleContext in ThreadLocal variable.
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// Rest of Web MVC configuration omitted
#Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(localeChangeInterceptor());
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale("fr");
return sessionLocaleResolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
}

Related

Add the language in the url / fr /, / en /, etc internationalization spring boot mvc

I followed this tutorial
https://www.baeldung.com/spring-boot-internationalization
I managed to get it to work: when I put the following url www.example.com/?lang=en I have the English version that is displayed.
However, I want to "convert" it so that the lang is directly in the example url www.example.com/en/ or www.example.com/fr/.
So i have this
#Configuration
public class Locale implements WebMvcConfigurer {
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
return slr;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
localeInterceptor.setParamName("lang");
return localeInterceptor;
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
I was thinking of using a filter, which will redirect to www.example.com/en/ or / fr / and if it can't find the language, configure the controller that if / {language} is null then it ignores it.
However, I do not know if my approach is good and especially I do not know how to retrieve the information of the language in the filter.
Could you help me ?
thank you

How to switch between externalized messages in Spring with thymeleaf?

Spring + thymeleaf
I want to display the message from Messages_pl.properties or Messages_en.properties depending on the need. And here's my problem as I don't know what to do when I want to view a message from the second file ( Messages_pl.properties is taken into account by default).
To access resource bundles by using specified basename I added the bean below to my #Configuration class:
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("Messages");
return messageSource;
}
Messages_pl.properties:
welcome.message=siemanko
Messages_en.properties:
welcome.message=hello
The fragment of my html file where I use this property:
<h1 th:text="#{message.welcome}"></h1>
Result: siemanko
what should I do to get the result as hello?
You can define on the same file Messages.properties the following :
welcome.message.pl=siemanko
welcome.message.en=hello
Then you can can a local resolver to make your project capable of determining the locale which is currently being used :
#Bean
public LocaleResolver localeResolver() {
return new CookieLocaleResolver();
}
Then add an interceptor of your language :
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
After that its simple to switch between languages , you just have to change the value of parameter lang on your link :
localhost:8080/your_page?lang=pl // will show siemanko on your page
localhost:8080/your_page?lang=en // will show hello on your page

Camel REST and Spring Security Java Configuration

I'm trying to set up Camel REST to use basic auth with a simple username/password from my application.properties and can't for the life of me seem to configure Camel Spring Security to do that. I'm trying to follow the Spring Security component documentation which seems to be missing the example of configuring the required beans. I found the missing example here under 'Controlling access to Camel routes' but this only shows the xml configuration.
How do I set up the required SpringSecurityAuthorizationPolicy bean? It needs an AuthenticationManager and an AccessDecisionManager and it also seems to require that I set its SpringSecurityAccessPolicy which I have no idea how to do.
I haven't gotten to test these yet, because I can't get my beans set up, but my rest route looks like:
rest("/ingest")
.post("/json").consumes("application/json")
.route()
.process(authProcessor)
.policy(authPolicy) // this is the bean I don't know how to configure
.to("direct:ingest")
.endRest();
and my AuthProcessor (taken from the camel component doc) looks like:
#Component
public class AuthProcessor implements Processor {
public void process(Exchange exchange) {
String userpass = new String(Base64.decodeBase64(exchange.getIn().getHeader("Authorization", String.class)));
String[] tokens = userpass.split(":");
// create an Authentication object
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(tokens[0], tokens[1]);
// wrap it in a Subject
Subject subject = new Subject();
subject.getPrincipals().add(authToken);
// place the Subject in the In message
exchange.getIn().setHeader(Exchange.AUTHENTICATION, subject);
}
}
and here's my broken bean configuration for what it's worth:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public SpringSecurityAuthorizationPolicy springSecurityAuthorizationPolicy(
AuthenticationManager authenticationManager, AccessDecisionManager accessDecisionManager) {
SpringSecurityAuthorizationPolicy policy = new SpringSecurityAuthorizationPolicy();
SpringSecurityAccessPolicy springSecurityAccessPolicy = new SpringSecurityAccessPolicy();
policy.setAuthenticationManager(authenticationManager);
policy.setAccessDecisionManager(accessDecisionManager);
policy.setSpringSecurityAccessPolicy(????);
return policy;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("pass").roles("USER");
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AccessDecisionManager accessDecisionManager() {
AffirmativeBased affirmativeBased = new AffirmativeBased(ImmutableList.of(
new RoleVoter()
));
affirmativeBased.setAllowIfAllAbstainDecisions(true);
return affirmativeBased;
}
}
I've been banging my head against the wall trying to understand this so an example of how to do this would be amazing. It looks like the xml configuration for what I want to do (in the second link) is simple enough but I can't seem to replicate it in Java configuration.
I know it's an old topic, but I ran into similar questions. I managed to get it working. Not by overriding the accessDecisionManager() method within the WebSecurityConfigurerAdapter class, but by constructing a new instance while building my SpringSecurityAuthorizationPolicy:
#Bean
public Policy adminPolicy(AuthenticationManager authenticationManager) {
RoleVoter roleVoter = new RoleVoter();
SpringSecurityAuthorizationPolicy policy = new SpringSecurityAuthorizationPolicy();
policy.setAuthenticationManager(authenticationManager);
policy.setAccessDecisionManager(new UnanimousBased(List.of(roleVoter)));
policy.setSpringSecurityAccessPolicy(new SpringSecurityAccessPolicy(roleVoter.getRolePrefix() + "<ROLE_NAME>");
return policy;
}

Spring session jdbc - How to add multiple HttpSessionIdResolver for a single application

I have a problem in injecting multiple HttpSessionIdResolver for a single spring application.
For normal web application I would like to use CookieHttpSessionIdResolver
For Rest API I would go for HeaderHttpSessionIdResolver and Rest API url will be like "/api/**"
Internally spring sets a bean and uses that bean for all request(In this case HeaderHttpSessionIdResolver
and my web stopped working because i dont set X-Auth-Token header for every request) but i would like to override it.
Could any one please help me.
Thank you.
#EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 3600)
public class SessionConfig extends AbstractHttpSessionApplicationInitializer{
#Autowired
#Qualifier("userDatabase")
private DataSource dataSource;
#Bean
public DataSource dataSource() {
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean(value = "httpSessionIdResolver")
public HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
#Bean(value = "cookieHttpSessionIdResolver")
public HttpSessionIdResolver cookieHttpSessionIdResolver() {
return new CookieHttpSessionIdResolver();
}
}
I overridden spring session to enable both cookie and header based session.
Now it's working fine.
Currently I'm checking for URL that contains /api/* and if it contains i'm using header based other wise cookie based session.

Spring Boot Controller Locale Not Changing with Parameter

I'm having some trouble with using Spring Boot with Kotlin to handle locale. I created these settings in my application.properties file:
spring.messages.basename=messages/messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8
Then created an autowired instance of MessageSource in my controller:
#Autowired
lateinit var messageSource: MessageSource
When put a locale in the url as a parameter, the parameter doesn't seem to get picked up when I call LocaleContextHolder.getLocale(), so it is always en_US. Though, I can manually pick it up using #RequestParam(value="locale") locale: Locale as a parameter to my controller function and use it from there in the controller function, but not in other functions. I thought that spring boot LocaleContextHolder was supposed to hold the current locale based on the request URL automatically for the whole session.
I read an older article that mentioned using a LocaleChangeInterceptor bean as well as beans for MessageSource and LocaleResolver in your main class, but another article said Spring Boot doesn't require that. I tried it anyway with no difference. These are the functions I used:
#Bean
open fun localeResolver(): LocaleResolver {
val slr = SessionLocaleResolver()
slr.setDefaultLocale(Locale.US)
return slr
}
#Bean
open fun localeChangeInterceptor(): LocaleChangeInterceptor {
val localeChangeInterceptor = LocaleChangeInterceptor()
localeChangeInterceptor.paramName = "locale"
return localeChangeInterceptor
}
#Bean
open fun messageSource(): ResourceBundleMessageSource {
val source = ResourceBundleMessageSource()
source.setBasenames("messages/messages")
source.setDefaultEncoding("UTF-8")
return source
}
Any suggestions on what to try next other than capturing the locale manually and making it a parameter in every function that gets called by the controller? Thanks!
OK, looks like the missing piece was implementing a WebMvcConfigurerAdapter, setting up a SessionLocaleResolver bean, and overriding the addInterceptors function to manually add my LocaleChangeInterceptor. I used a separate Configuration class to do this.
#Configuration
open class CustomWebMvcConfigurerAdapter : WebMvcConfigurerAdapter() {
//internationalization beans
#Bean
open fun localeResolver(): LocaleResolver {
val slr = SessionLocaleResolver()
slr.setDefaultLocale(Locale.US)
return slr
}
#Bean
open fun localeChangeInterceptor(): LocaleChangeInterceptor {
val localeChangeInterceptor = LocaleChangeInterceptor()
localeChangeInterceptor.paramName = "locale"
return localeChangeInterceptor
}
override fun addInterceptors(registry: InterceptorRegistry?) {
registry?.addInterceptor(localeChangeInterceptor())
super.addInterceptors(registry)
}
}
I guess I misunderstood, thinking that Spring Boot handled the LocaleChangeInterceptor on it's own if you created the proper bean, but I guess you have to still override a WebMvcConfigurerAdapter and force the interceptor in there. If I've missed something and someone has a cleaner solution, I'd be happy to give you the accepted answer since what I'm doing here just feels like a messy workaround.

Resources