spring security示例,cas认证整合
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/Application.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/Application.java
new file mode 100644
index 0000000..4334545
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/Application.java
@@ -0,0 +1,13 @@
+package com.supwisdom.leaveschool.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class, args);
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/config/PasswordEncoderConfig.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/config/PasswordEncoderConfig.java
new file mode 100644
index 0000000..9b2385a
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/config/PasswordEncoderConfig.java
@@ -0,0 +1,24 @@
+package com.supwisdom.leaveschool.app.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.factory.PasswordEncoderFactories;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+public class PasswordEncoderConfig {
+  
+  private static final Logger logger = LoggerFactory.getLogger(PasswordEncoderConfig.class);
+  
+  @Bean
+  public PasswordEncoder passwordEncoder() {
+    
+    PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
+    
+    logger.debug("PasswordEncoderConfig passwordEncoder is {}", passwordEncoder);
+    return passwordEncoder;
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/config/UserDetailsServiceConfig.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/config/UserDetailsServiceConfig.java
new file mode 100644
index 0000000..9419f46
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/config/UserDetailsServiceConfig.java
@@ -0,0 +1,23 @@
+package com.supwisdom.leaveschool.app.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+import com.supwisdom.leaveschool.app.security.core.userdetails.MyUserDetailsService;
+
+@Configuration
+public class UserDetailsServiceConfig {
+
+  private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceConfig.class);
+  
+  @Bean
+  public UserDetailsService userDetailsService(MyUserDetailsService myUserDetailsService) throws Exception {
+    
+    logger.debug("UserDetailsServiceConfig userDetailsService is {}", myUserDetailsService);
+    return myUserDetailsService;
+  }
+  
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/api/ApiUserController.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/api/ApiUserController.java
new file mode 100644
index 0000000..6cf50e1
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/api/ApiUserController.java
@@ -0,0 +1,30 @@
+package com.supwisdom.leaveschool.app.controller.api;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.util.MimeTypeUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/user")
+public class ApiUserController {
+  
+
+  /**
+   * curl -i -s -X GET -H 'Accept:application/json' 'http://admin:password@localhost:8080/api/user/greeting/abc'
+   *
+   * @param name
+   * @return
+   */
+  @GetMapping(path = "/greeting/{name}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+  public Map<String, Object> greeting(@PathVariable String name) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("message", "Good " + name);
+    return result;
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/MainController.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/MainController.java
new file mode 100755
index 0000000..8e55ddf
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/MainController.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2002-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.supwisdom.leaveschool.app.controller.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@Controller
+public class MainController {
+
+	@RequestMapping("/")
+	public String root() {
+		return "redirect:/web/index";
+	}
+
+	@RequestMapping("/web/index")
+	public String index() {
+		return "web/index";
+	}
+
+	@RequestMapping(value = "/web/login")
+	public String login() {
+		return "web/login";
+	}
+
+	@RequestMapping(value = "/web/login", method = RequestMethod.POST)
+	public String postLogin() {
+		// TODO Enable form login with Spring Security (trigger error for now)
+		return "redirect:/web/login-error";
+	}
+
+	@RequestMapping("/web/login-error")
+	public String loginError(Model model) {
+		model.addAttribute("loginError", true);
+		return "web/login";
+	}
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/admin/WebAdminRoleController.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/admin/WebAdminRoleController.java
new file mode 100644
index 0000000..d54ae87
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/admin/WebAdminRoleController.java
@@ -0,0 +1,5 @@
+package com.supwisdom.leaveschool.app.controller.web.admin;
+
+public class WebAdminRoleController {
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/admin/WebAdminUserController.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/admin/WebAdminUserController.java
new file mode 100644
index 0000000..0dedae4
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/controller/web/admin/WebAdminUserController.java
@@ -0,0 +1,15 @@
+package com.supwisdom.leaveschool.app.controller.web.admin;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping("/web/admin/user")
+public class WebAdminUserController {
+
+  @RequestMapping("/index")
+  public String userIndex() {
+    return "web/admin/user/index";
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/security/core/userdetails/MyUser.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/security/core/userdetails/MyUser.java
new file mode 100644
index 0000000..3bf7a4e
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/security/core/userdetails/MyUser.java
@@ -0,0 +1,30 @@
+package com.supwisdom.leaveschool.app.security.core.userdetails;
+
+import java.util.Collection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+
+public class MyUser extends User {
+  
+  //private static final Log logger = LogFactory.getLog(MyUser.class);
+  private static final Logger logger = LoggerFactory.getLogger(MyUser.class);
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 5438858716934315373L;
+  
+  public MyUser(String username, String password,
+      Collection<? extends GrantedAuthority> authorities) {
+    this(username, password, true, true, true, true, authorities);
+  }
+
+  public MyUser(String username, String password, boolean enabled, boolean accountNonExpired,
+      boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
+    super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/app/security/core/userdetails/MyUserDetailsService.java b/samples/security/src/main/java/com/supwisdom/leaveschool/app/security/core/userdetails/MyUserDetailsService.java
new file mode 100644
index 0000000..b4ea3d0
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/app/security/core/userdetails/MyUserDetailsService.java
@@ -0,0 +1,40 @@
+package com.supwisdom.leaveschool.app.security.core.userdetails;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MyUserDetailsService implements UserDetailsService {
+  
+  //private static final Log logger = LogFactory.getLog(MyUserDetailsService.class);
+  private static final Logger logger = LoggerFactory.getLogger(MyUserDetailsService.class);
+  
+  @Autowired
+  PasswordEncoder passwordEncoder;
+  
+  @Override
+  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+    
+    logger.debug("MyUserDetailsService.loadUserByUsername({})", username);
+    
+    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+    authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+    
+    MyUser myUser = new MyUser("user", passwordEncoder.encode("password"), authorities);
+    logger.debug("myUser is {}", myUser);
+    
+    return myUser;
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/CasConfiguration.java b/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/CasConfiguration.java
new file mode 100644
index 0000000..b95cf53
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/CasConfiguration.java
@@ -0,0 +1,136 @@
+package com.supwisdom.leaveschool.security.autoconfigure;
+
+import org.jasig.cas.client.session.SingleSignOutFilter;
+import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.cas.ServiceProperties;
+import org.springframework.security.cas.authentication.CasAuthenticationProvider;
+import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
+import org.springframework.security.cas.web.CasAuthenticationFilter;
+import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+import org.springframework.security.web.session.ConcurrentSessionFilter;
+import org.springframework.security.web.session.HttpSessionEventPublisher;
+import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
+
+@Configuration
+@EnableConfigurationProperties(CasProperties.class)
+public class CasConfiguration {
+  
+  @Autowired
+  private AuthenticationManager authenticationManager;
+
+  @Autowired
+  private UserDetailsService userDetailsService;
+  
+  @Autowired
+  private CasProperties casProperties;
+
+  // SpringSecurity内置的session监听器
+  @Bean
+  public HttpSessionEventPublisher httpSessionEventPublisher() {
+    return new HttpSessionEventPublisher();
+  }
+
+  @Bean
+  public ConcurrentSessionFilter sessionInfomationExpiredStategy() {
+    ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry());
+    return concurrentSessionFilter;
+  }
+
+  @Bean
+  public SimpleRedirectInvalidSessionStrategy simpleRedirectInvalidSessionStrategy() {
+    return new SimpleRedirectInvalidSessionStrategy("/web/login?error");
+  }
+
+  @Bean
+  public SessionRegistry sessionRegistry() {
+    return new SessionRegistryImpl();
+  }
+
+  /** 认证的入口 */
+  @Bean
+  public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
+    CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
+    casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
+    casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
+    return casAuthenticationEntryPoint;
+  }
+
+  /** 指定service相关信息 */
+  @Bean
+  public ServiceProperties serviceProperties() {
+    ServiceProperties serviceProperties = new ServiceProperties();
+    serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
+    serviceProperties.setAuthenticateAllArtifacts(true);
+    return serviceProperties;
+  }
+
+  /** CAS认证过滤器 */
+  @Bean
+  public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
+    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
+    casAuthenticationFilter.setAuthenticationManager(authenticationManager);
+    casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
+    casAuthenticationFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
+    casAuthenticationFilter.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler());
+    casAuthenticationFilter.setServiceProperties(serviceProperties());
+    casAuthenticationFilter.setAuthenticationDetailsSource(new ServiceAuthenticationDetailsSource(serviceProperties()));
+    // casAuthenticationFilter.setAuthenticationDetailsSource(customUserDetailsService());
+    return casAuthenticationFilter;
+  }
+
+  /** cas 认证 Provider */
+  @Bean
+  public CasAuthenticationProvider casAuthenticationProvider() {
+    CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
+    // casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
+    // casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。
+    casAuthenticationProvider.setUserDetailsService(userDetailsService);
+    casAuthenticationProvider.setServiceProperties(serviceProperties());
+    casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
+    // casAuthenticationProvider.setTicketValidator(cas20ProxyTicketValidator());
+    casAuthenticationProvider.setKey("casAuthenticationProviderKey");
+    return casAuthenticationProvider;
+  }
+
+  /** 用户自定义的AuthenticationUserDetailsService */
+  // @Bean
+  // public AuthenticationUserDetailsService<CasAssertionAuthenticationToken>
+  // customUserDetailsService(){
+  // return new CustomUserDetailsService();
+  // }
+
+  @Bean
+  public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
+    return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
+  }
+
+  /** 单点登出过滤器 */
+  @Bean
+  public SingleSignOutFilter singleSignOutFilter() {
+    SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
+    singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());
+    singleSignOutFilter.setIgnoreInitConfiguration(true);
+    return singleSignOutFilter;
+  }
+
+  /** 请求单点退出过滤器 */
+  @Bean
+  public LogoutFilter logoutFilter() {
+    LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());
+    logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());
+    return logoutFilter;
+  }
+
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/CasProperties.java b/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/CasProperties.java
new file mode 100644
index 0000000..e6628de
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/CasProperties.java
@@ -0,0 +1,75 @@
+package com.supwisdom.leaveschool.security.autoconfigure;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+//import org.springframework.stereotype.Component;
+
+//@Component
+@ConfigurationProperties
+public class CasProperties {
+    @Value("${cas.server.host.url}")
+    private String casServerUrl;
+
+    @Value("${cas.server.host.login_url}")
+    private String casServerLoginUrl;
+
+    @Value("${cas.server.host.logout_url}")
+    private String casServerLogoutUrl;
+
+    @Value("${app.server.host.url}")
+    private String appServerUrl;
+
+    @Value("${app.login.url}")
+    private String appLoginUrl;
+
+    @Value("${app.logout.url}")
+    private String appLogoutUrl;
+
+    public String getCasServerUrl() {
+        return casServerUrl;
+    }
+
+    public void setCasServerUrl(String casServerUrl) {
+        this.casServerUrl = casServerUrl;
+    }
+
+    public String getCasServerLoginUrl() {
+        return casServerLoginUrl;
+    }
+
+    public void setCasServerLoginUrl(String casServerLoginUrl) {
+        this.casServerLoginUrl = casServerLoginUrl;
+    }
+
+    public String getCasServerLogoutUrl() {
+        return casServerLogoutUrl;
+    }
+
+    public void setCasServerLogoutUrl(String casServerLogoutUrl) {
+        this.casServerLogoutUrl = casServerLogoutUrl;
+    }
+
+    public String getAppServerUrl() {
+        return appServerUrl;
+    }
+
+    public void setAppServerUrl(String appServerUrl) {
+        this.appServerUrl = appServerUrl;
+    }
+
+    public String getAppLoginUrl() {
+        return appLoginUrl;
+    }
+
+    public void setAppLoginUrl(String appLoginUrl) {
+        this.appLoginUrl = appLoginUrl;
+    }
+
+    public String getAppLogoutUrl() {
+        return appLogoutUrl;
+    }
+
+    public void setAppLogoutUrl(String appLogoutUrl) {
+        this.appLogoutUrl = appLogoutUrl;
+    }
+}
diff --git a/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/SecurityAutoConfiguration.java b/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/SecurityAutoConfiguration.java
new file mode 100644
index 0000000..69e0704
--- /dev/null
+++ b/samples/security/src/main/java/com/supwisdom/leaveschool/security/autoconfigure/SecurityAutoConfiguration.java
@@ -0,0 +1,215 @@
+package com.supwisdom.leaveschool.security.autoconfigure;
+
+import org.jasig.cas.client.session.SingleSignOutFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.cas.authentication.CasAuthenticationProvider;
+import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
+import org.springframework.security.cas.web.CasAuthenticationFilter;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+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.session.SessionRegistry;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.User.UserBuilder;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.factory.PasswordEncoderFactories;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.security.web.session.ConcurrentSessionFilter;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityAutoConfiguration {
+
+  private static final Logger logger = LoggerFactory.getLogger(SecurityAutoConfiguration.class);
+  
+  @Bean
+  @ConditionalOnMissingBean({UserDetailsService.class})
+  public UserDetailsService userDetailsService() throws Exception {
+    
+    // ensure the passwords are encoded properly
+    @SuppressWarnings("deprecation")
+    UserBuilder users = User.withDefaultPasswordEncoder();
+    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+    manager.createUser(users.username("user").password("password").roles("USER").build());
+    manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());
+    
+    logger.debug("SecurityAutoConfiguration userDetailsService is {}", manager);
+    return manager;
+  }
+  
+  @Bean
+  @ConditionalOnMissingBean({PasswordEncoder.class})
+  public PasswordEncoder passwordEncoder() {
+    
+    PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
+    
+    logger.debug("SecurityAutoConfiguration passwordEncoder is {}", passwordEncoder);
+    return passwordEncoder;
+  }
+
+  @Configuration
+  @Order(0)
+  public static class BaseWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+
+    @Bean(name = "authenticationManager")
+    @Override
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+      return super.authenticationManagerBean();
+    }
+    
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+      
+      http.antMatcher("/base/**")
+        .authorizeRequests()
+          .anyRequest()
+          .permitAll();
+    }
+
+  }
+
+  // 本地认证配置
+  @Configuration
+  @ConditionalOnProperty(name="security.cas.enabled", havingValue="false")
+  @Order(10)
+  public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+
+    @Autowired
+    private UserDetailsService userDetailsService;
+
+    @Autowired
+    private PasswordEncoder passwordEncoder;
+
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+      http
+        .antMatcher("/web/**")
+        .authorizeRequests()
+          .antMatchers("/web/index").permitAll()
+          .antMatchers("/web/**").authenticated()
+          .anyRequest().authenticated()
+          .and()
+        //.rememberMe()
+        //  .and()
+        .formLogin()
+          .loginPage("/web/login")
+          .permitAll()
+          //.failureUrl("/login-error")
+          //.permitAll()
+          .and()
+        .logout()
+          .logoutUrl("/web/logout")
+          .permitAll();
+    }
+
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+
+      logger.debug("userDetailsService is {}", userDetailsService);
+      logger.debug("passwordEncoder is {}", passwordEncoder);
+      auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
+    }
+
+  }
+
+  // CAS 认证配置
+  @Configuration
+  @ConditionalOnProperty(name="security.cas.enabled", havingValue="true")
+  @Order(20)
+  @Import(CasConfiguration.class)
+  public static class CASLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+
+    @Autowired
+    private CasAuthenticationProvider casAuthenticationProvider;
+
+    @Autowired
+    private CasAuthenticationEntryPoint casAuthenticationEntryPoint;
+
+    @Autowired
+    private CasAuthenticationFilter casAuthenticationFilter;
+
+    @Autowired
+    private LogoutFilter logoutFilter;
+
+    @Autowired
+    private SingleSignOutFilter singleSignOutFilter;
+
+    @Autowired
+    private ConcurrentSessionFilter sessionInfomationExpiredStategy;
+
+    @Autowired
+    private SessionRegistry sessionRegistry;
+
+    /** 定义认证用户信息获取来源,密码校验规则等 */
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+      super.configure(auth);
+      auth.authenticationProvider(casAuthenticationProvider);
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+      http
+        .antMatcher("/web/**")
+        .authorizeRequests()
+          .antMatchers("/web/index", "/web/login").permitAll()
+          .antMatchers("/web/**").authenticated()
+          .anyRequest().authenticated()
+          .and()
+        .formLogin()
+          .loginPage("/web/login")
+          .permitAll()
+          .and()
+        .logout()
+          .logoutUrl("/web/logout")
+          .permitAll();
+
+      http.csrf().disable();
+
+      //http.sessionManagement().sessionFixation().none();
+      //http.sessionManagement().sessionAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
+      //http.sessionManagement().maximumSessions(-1).sessionRegistry(sessionRegistry);
+
+      // casAuthenticationFilter.setAuthenticationManager(authenticationManager());
+
+      http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint);
+      http.addFilterAt(casAuthenticationFilter, CasAuthenticationFilter.class);
+      http.addFilterAt(logoutFilter, LogoutFilter.class);
+      http.addFilterAt(singleSignOutFilter, CasAuthenticationFilter.class);
+      http.addFilterAt(sessionInfomationExpiredStategy, ConcurrentSessionFilter.class);
+      // http.addFilterAt(filterSecurityInterceptor, FilterSecurityInterceptor.class);
+
+    }
+
+  }
+
+  @Configuration
+  @Order(50)
+  public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+      http
+        .antMatcher("/api/**")
+        .authorizeRequests()
+          .anyRequest().hasRole("ADMIN")
+          .and()
+        .httpBasic();
+    }
+
+  }
+
+}
diff --git a/samples/security/src/main/resources/META-INF/spring.factories b/samples/security/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..3af7d9b
--- /dev/null
+++ b/samples/security/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,3 @@
+# Auto Configure
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.supwisdom.leaveschool.security.autoconfigure.SecurityAutoConfiguration
\ No newline at end of file
diff --git a/samples/security/src/main/resources/application.properties b/samples/security/src/main/resources/application.properties
new file mode 100755
index 0000000..ffc5d59
--- /dev/null
+++ b/samples/security/src/main/resources/application.properties
@@ -0,0 +1,28 @@
+server.port=8080
+
+## logging
+logging.level.root=INFO
+logging.level.org.springframework.web=INFO
+logging.level.com.supwisdom.leaveschool.security=DEBUG
+
+## thymeleaf
+spring.thymeleaf.cache=false
+
+
+## 认证方式,是否开启 CAS 认证
+security.cas.enabled=true
+
+## CAS
+#应用访问地址
+app.server.host.url=http://localhost:8080
+#应用登录地址
+app.login.url=/web/caslogin
+#应用登出地址
+app.logout.url=/web/logout
+
+#CAS服务地址
+cas.server.host.url=http://101.231.81.202:9080/cas
+#CAS服务登录地址
+cas.server.host.login_url=${cas.server.host.url}/login
+#CAS服务登出地址
+cas.server.host.logout_url=${cas.server.host.url}/logout?service=${app.server.host.url}
diff --git a/samples/security/src/main/resources/static/assets/css/CSS b/samples/security/src/main/resources/static/assets/css/CSS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/security/src/main/resources/static/assets/css/CSS
diff --git a/samples/security/src/main/resources/static/assets/css/main.css b/samples/security/src/main/resources/static/assets/css/main.css
new file mode 100755
index 0000000..5e6687a
--- /dev/null
+++ b/samples/security/src/main/resources/static/assets/css/main.css
@@ -0,0 +1,13 @@
+body {
+    font-family: sans;
+    font-size: 1em;
+}
+
+p.error {
+    font-weight: bold;
+    color: red;
+}
+
+div.logout {
+    float: right;
+}
\ No newline at end of file
diff --git a/samples/security/src/main/resources/static/assets/images/IMAGES b/samples/security/src/main/resources/static/assets/images/IMAGES
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/security/src/main/resources/static/assets/images/IMAGES
diff --git a/samples/security/src/main/resources/static/assets/js/JS b/samples/security/src/main/resources/static/assets/js/JS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/security/src/main/resources/static/assets/js/JS
diff --git a/samples/security/src/main/resources/templates/web/admin/user/index.html b/samples/security/src/main/resources/templates/web/admin/user/index.html
new file mode 100644
index 0000000..2326203
--- /dev/null
+++ b/samples/security/src/main/resources/templates/web/admin/user/index.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
+<head>
+<title>Hello Spring Security</title>
+<meta charset="utf-8" />
+<link rel="stylesheet" href="/assets/css/main.css" th:href="@{/assets/css/main.css}" />
+</head>
+<body>
+  <div th:substituteby="web/index::logout"></div>
+  <h1>This is a secured page!</h1>
+  <p>
+    <a href="/web/index" th:href="@{/web/index}">Back to home page</a>
+  </p>
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/security/src/main/resources/templates/web/index.html b/samples/security/src/main/resources/templates/web/index.html
new file mode 100644
index 0000000..b9dcbf4
--- /dev/null
+++ b/samples/security/src/main/resources/templates/web/index.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<!-- <html xmlns:th="http://www.thymeleaf.org"> -->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
+<head>
+<title>Hello Spring Security</title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta charset="utf-8" />
+<link rel="stylesheet" href="/assets/css/main.css" th:href="@{/assets/css/main.css}" />
+</head>
+<body>
+  <div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
+    Logged in user: <span sec:authentication="name"></span> | 
+    Roles: <span sec:authentication="principal.authorities"></span>
+    <div>
+      <form action="#" th:action="@{/web/logout}" method="post">
+        <input type="submit" value="Logout" />
+      </form>
+    </div>
+  </div>
+  <h1>Hello Spring Security</h1>
+  <p>This is an unsecured page, but you can access the secured pages after authenticating.</p>
+  <ul>
+    <li>Go to the <a href="/web/admin/user/index" th:href="@{/web/admin/user/index}">secured pages</a></li>
+  </ul>
+</body>
+</html>
diff --git a/samples/security/src/main/resources/templates/web/login.html b/samples/security/src/main/resources/templates/web/login.html
new file mode 100755
index 0000000..1bc5e4d
--- /dev/null
+++ b/samples/security/src/main/resources/templates/web/login.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
+    <head>
+        <title>Login page</title>
+        <meta charset="utf-8" />
+        <link rel="stylesheet" href="/assets/css/main.css" th:href="@{/assets/css/main.css}" />
+	</head>
+    <body>
+        <h1>Login page</h1>
+        <p>Example user: user / password</p>
+        <p th:if="${loginError}" class="error">Wrong user or password</p>
+        <div th:if="${param.error}" class="alert alert-error">Invalid username and password.</div>
+        <div th:if="${param.logout}" class="alert alert-success">You have been logged out.</div>
+        
+        <form th:action="@{/web/login}" method="post">
+            <label for="username">Username</label>:
+            <input type="text" id="username" name="username" autofocus="autofocus" /> <br />
+            <label for="password">Password</label>:
+            <input type="password" id="password" name="password" /> <br />
+            <input type="submit" value="Log in" />
+        </form>
+        <p><a href="/index" th:href="@{/index}">Back to home page</a></p>
+    </body>
+</html>