Spring Security 借助一系列Servlet Filter 來提供安全性功能,但是借助Spring的小技巧,我們只需要配置一個Filer就可以了,DelegatingFilterProxy是一個特殊的Servlet Filter,它本身所做的工作並不多,只是將工作委托給一個javax.servlet.Filter 的實現類,這個實現類作為一個bean注冊再Spring應用的上下文中。
如果了解過用xml配置spring security的朋友就知道,用基於xml配置Spring Security過程繁瑣,而且不容易學習和入門,但是基於javaConfig和注解則大大簡化了這一配置,下面我們來看看是如何用java的方式配置Spring Security
首先我們需要配置DelegatingFilterProxy,我們只需要拓展一個新類,該類實現了WebApplicationInitializer,因此Spring會發現它並用他在Web容器中注冊DelegatingFilterProxy。
public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer { }
接下來我們需要啟用Web安全性功能,也是只需要拓展一個類,Spring Security 必須配置在一個實現了WebSecurityConfigurer 的bean中,或者拓展WebSecurityConfigurerAdapter 。在Spring 應用上下文中,任何實現了WebSecurityConfigurerAdapter 的bean都可以用來配置Spring Security。常用的配置已貼上,也全都寫上了對應的注釋。
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailServiceImpl userDetailService; //對每個請求進行細粒度安全性控制的關鍵在於重載一下方法 @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests()//該方法所返回的對象的方法來配置請求級別的安全細節 .antMatchers("/login") .permitAll()//對於登錄路徑不進行攔截 .antMatchers("/show").authenticated()//authenticated()表示允許過的用戶訪問 .and() .formLogin()//配置登錄頁面 .loginPage("/login")//登錄頁面的訪問路徑 .loginProcessingUrl("/check")//登錄頁面下表單提交的路徑 .failureUrl("/login")//登錄失敗後跳轉的路徑 .defaultSuccessUrl("/show")//登錄成功後默認跳轉的路徑 .and() .csrf()//啟用防跨站偽請求攻擊,默認啟用 .and() .logout()//用戶退出操作 .logoutUrl("/logout")//用戶退出所訪問的路徑,需要使用Post方式 .permitAll() .logoutSuccessUrl("/login?logout=true") .and() .authorizeRequests() // //定義路徑保護的配置方法 // .antMatchers(HttpMethod.GET,"/admin") // .authenticated() .antMatchers(HttpMethod.GET,"/message/**","/object/**").hasRole("USER") .anyRequest().permitAll() .and() .rememberMe()//啟用記住我功能 .tokenValiditySeconds(2419200) ; } //配置Spring Security的Filter鏈 @Override public void configure(WebSecurity web) throws Exception { super.configure(web); } //配置user-detail服務 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailService) .passwordEncoder(new StandardPasswordEncoder("53cr3t"))//密碼加密方式 ; // auth.inMemoryAuthentication() //內置用戶 // .withUser("user").password("user").roles("USER"); } }
需要注意的有幾點,如果是用xml配置的springmvc環境下,基於javaConfig和注解配置Spring Security同樣適用,只需要確保Spring的上下文能夠掃描到上述的兩個類即可。
如果在JSP頁面下使用Spring的表單標簽,該標簽默認會自動添加隱藏的CSRF token標簽,即防跨站偽請求攻擊,如果沒有使用Spring的表單標簽,則需要手動添加以下標簽,尤其是進行logout登出時表單提交,在Form標簽內必須保護以下內容。
<input type="hiden" name="${_csrf.parameterName}" value="${_csrf.token}"}
下面是登錄頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %> <html> <head> <title>login</title> </head> <body> <sf:form action="check" method="post" commandName="user" > 用戶名:<sf:input path="username"></sf:input> password:<sf:password path="password"></sf:password> <input id="remember_me" name="remember-me" type="checkbox"> <label for="remember_me" class="inline">Remember me</label> <input type="submit" value="提交" > </sf:form> </body> </html>
登出頁面
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %> <html> <head> <title>User Manager</title> </head> <body> <sf:form id="logoutForm" action="${ctx}/logout" method="post"> <a href="#" onclick="document.getElementById('logoutForm').submit();">注銷</a> </sf:form> </body> </html>
如果我們想要配置自定義認證和授權服務,則需要實現UserDetailsService
public class UserDetailServiceImpl implements UserDetailsService { private static Logger logger=Logger.getLogger(UserDetailServiceImpl.class); @Autowired private IUserService userService; @Autowired private IRoleService roleService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.info("===========授權============"); User user= null; List<Role> role=null; try { user = userService.findUserByUsername(username); role=roleService.listRoleByUserId(user.getId()); logger.info("用戶角色為:"+role); } catch (BaseException e) { e.printStackTrace(); } List<GrantedAuthority> list= new ArrayList<GrantedAuthority>(); list.add(new SimpleGrantedAuthority("ROLE_"+role)); org.springframework.security.core.userdetails.User authUser = new org.springframework.security.core.userdetails.User (user.getUsername(),user.getPassword(),list); return authUser; } }
該配置將安全級別細分到角色。重寫的方法傳來的參數為登錄的username,再通過該參數從數據庫中獲取用戶,以及相對應的權限,最終通過 將用戶、密碼、權限傳入並實例化org.springframework.security.core.userdetails.User ,從而授權結束。配置安全路徑或者方法中的權限依據上述方法中獲取並綁定的權限。至此我們就可以對路徑進行安全權限保護了。
Spring Security 學習筆記 http://www.linuxidc.com/Linux/2016-10/135820.htm
Spring Security3.1高級詳細開發指南 PDF http://www.linuxidc.com/Linux/2016-05/131482.htm
Spring Security 學習之數據庫認證 http://www.linuxidc.com/Linux/2014-02/97407.htm
Spring Security 學習之LDAP認證 http://www.linuxidc.com/Linux/2014-02/97406.htm
Spring Security 學習之OpenID認證 http://www.linuxidc.com/Linux/2014-02/97405.htm
Spring Security 學習之X.509認證 http://www.linuxidc.com/Linux/2014-02/97404.htm
Spring Security 學習之HTTP基本認證和HTTP摘要認證 http://www.linuxidc.com/Linux/2014-02/97403.htm
Spring Security 學習之HTTP表單驗證 http://www.linuxidc.com/Linux/2014-02/97402.htm
Spring Security異常之You must provide a configuration attribute http://www.linuxidc.com/Linux/2015-02/113364.htm
Spring Security 的詳細介紹:請點這裡
Spring Security 的下載地址:請點這裡