http://books.zkoss.org/zk-mvvm-book/8.0/index.html
https://www.zkoss.org/documentation#References
+##### Spring ZK Security
+
+https://www.zkoss.org/wiki/ZK_Spring_Essentials/Working_with_ZK_Spring/Working_with_ZK_Spring_Security/Secure_a_ZK_Application_with_Spring_Security
+https://www.zkoss.org/wiki/ZK_Spring_Essentials/Working_with_ZK_Spring/Working_with_ZK_Spring_Security/Add_Security_in_the_View_Layer
+(To enable remove @SpringBootApplication with exludes and @ComponentScan)
+
##### ZK Style
https://www.zkoss.org/wiki/ZK_Developer's_Reference/Theming_and_Styling/ZK_Official_Themes
package hu.user.lis.app;
+import hu.user.lis.ui.config.WebSecurityConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.SpringVersion;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
-@SpringBootApplication(scanBasePackages = {"hu.user.lis"})
+//@SpringBootApplication(scanBasePackages = {"hu.user.lis"})
+@SpringBootApplication(exclude = {
+ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class,
+ org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration.class}
+)
+@ComponentScan(basePackages = {"hu.user.lis"}, excludeFilters = {
+ @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WebSecurityConfig.class)})
@EnableWebMvc
public class Main extends SpringBootServletInitializer implements ApplicationListener<ContextRefreshedEvent> {
// AnsiConsole.systemUninstall();
}
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
- logger.info("Starting configure");
- return builder.sources(Main.class);
- }
-
-
private static void dumpComponents(ApplicationContext applicationContext) {
for (String beanName : applicationContext.getBeanDefinitionNames()) {
logger.info("Found {}", beanName);
}
}
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+ logger.info("Starting configure");
+ return builder.sources(Main.class);
+ }
+
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
logger.info("Context refreshed");
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
--- /dev/null
+package hu.user.lis.ui.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+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.provisioning.InMemoryUserDetailsManager;
+
+/**
+ * This is an example of minimal configuration for ZK + Spring Security, we open as less access as possible to run a ZK-based application.
+ * Please understand the configuration and modify it upon your requirement.
+ */
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+ private static final String ZUL_FILES = "/zkau/web/**/*.zul";
+ private static final String ZK_RESOURCES = "/zkres/**";
+ // allow desktop cleanup after logout or when reloading login page
+ private static final String REMOVE_DESKTOP_REGEX = "/zkau\\?dtid=.*&cmd_0=rmDesktop&.*";
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // you need to disable spring CSRF to make ZK AU pass security filter
+ // ZK already sends a AJAX request with a built-in CSRF token,
+ // please refer to https://www.zkoss.org/wiki/ZK%20Developer's%20Reference/Security%20Tips/Cross-site%20Request%20Forgery
+ http.csrf().disable();
+ http.authorizeRequests()
+ .antMatchers(ZUL_FILES).denyAll() // block direct access to zul under class path web resource folder
+ .antMatchers(HttpMethod.GET, ZK_RESOURCES).permitAll() // allow zk resources
+ .regexMatchers(HttpMethod.GET, REMOVE_DESKTOP_REGEX).permitAll() // allow desktop cleanup
+ .requestMatchers(req -> "rmDesktop".equals(req.getParameter("cmd_0"))).permitAll() // allow desktop cleanup from ZATS
+ .mvcMatchers("/", "/login", "/logout").permitAll() //permit the URL for login and logout
+ .mvcMatchers("/secure").hasRole("USER")
+ .anyRequest().authenticated() //enforce all requests to be authenticated
+ .and()
+ .formLogin()
+ .loginPage("/login").defaultSuccessUrl("/secure/main")
+ .and()
+ .logout().logoutUrl("/logout").logoutSuccessUrl("/");
+ }
+
+ /**
+ * Creates an {@link InMemoryUserDetailsManager} for demo/testing purposes only. DON'T use this in production, see: {@link User#withUserDetails}!
+ *
+ * @return userDetailsService
+ */
+ @Bean
+ @Override
+ public UserDetailsService userDetailsService() {
+ UserDetails user =
+ User.withDefaultPasswordEncoder()
+ .username("user")
+ .password("password")
+ .roles("USER")
+ .build();
+
+ return new InMemoryUserDetailsManager(user);
+ }
+}
\ No newline at end of file
--- /dev/null
+<zk xmlns:n="native">
+ <n:form action="/login" method="POST">
+ <grid width="450px">
+ <columns>
+ <column width="160px" />
+ <column width="280px" />
+ </columns>
+ <rows>
+ <row spans="2" align="center">
+ <label value="LOGIN"/>
+ </row>
+ <row>
+ <label value="User :"/>
+ <textbox name="username" value="user"/></row>
+ <row>
+ <label value="Password :"/>
+ <textbox type="password" name="password" value="password"/> </row>
+ <row spans="2" align="right">
+ <hlayout>
+ <button type="reset" label="Reset" /> <button type="submit" label="Login" />
+ </hlayout>
+ </row>
+ </rows>
+ </grid>
+ </n:form>
+</zk>
\ No newline at end of file