springboot內使用spring security

攔截請求

對每個請求進行細粒度安全性控制的關鍵在於重載configure(HttpSecurity)方法。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()                     
            .antMatchers("/test").authenticated()
            //.antMatchers("/test","/tests").authenticated()
            .antMatchers(HttpMethod.POST,"/tests").authenticated()
            .anyRequest().permitAll();
}

我們首先調用authorizeRequests(),然後調用該方法所返回的對象的方法來配置請求級別的安全性細節。其中,第一次調用antMatchers()指定了對/test路徑的請求需要認證。第二次調用antMatchers()更爲具體,說明對/tests路徑的HTTP POST請求必須要經過認證。最後anyRequest().permitAll()說明其他所有的請求都是允許的,不需要認證和任何的權限。

antMatchers()方法中設定的路徑支持Ant風格的通配符。

當然,antMatchers()同時也可以指定多個路徑:

.antMatchers("/test","/tests").authenticated()

authenticated()要求在執行該請求時,必須已經登錄了應用,否則會出現如下錯誤。permitAll()方法允許請求沒有任何的安全限制。

用來定義如何保護路徑的方法 :

我們還可以修改之前的configure()方法,要求用戶不僅需要認證,還要具備ROLE_USER權限。

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //.antMatchers("/test","/tests").authenticated()
                .antMatchers("/haha/**").hasAuthority("ROLE_USER")
                .antMatchers("/haha/**").hasRole("USER")
                //.antMatchers(HttpMethod.POST,"/tests").authenticated()
                .anyRequest().permitAll();
    }

hasRole()是hasAuthority()的縮寫,它會自動使用ROLE_前綴。

我們可以將任意的antMatchers()、anyRequest()連接起來,以滿足Web應用安全規則的需要。

使用Spring表達式進行保護

表9.4.大多數方法都是一維的,也就是說不能疊加使用。但藉助access()方法,我們也可以將SpEL作爲聲明訪問限制的一種方式。

.antMatchers("/haha/**").hasRole("USER")
.antMatchers("/haha/**").access("hasRole('USER')")

這兩個效果是等價的。表9.5列出了Spring Security支持的所有SpEL表達式。

強制通道的安全性

我們都知道HTTP發送的數據都是不加密的,所以對於一些敏感信息要通過HTTPS來加密發送。
傳遞到config()方法中HttpSecurity對象,除了具有authorizeRequests()方法以外,還有一個requiresChannel()方法,藉助這個方法能夠爲各種URL模式聲明所要求的通道。

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/test","/tests").authenticated()
                .anyRequest().permitAll()
                .and()
                .requiresChannel()
                .antMatchers("/haha/ha").requiresSecure()    //需要HTTPS
                ;
    }

與之相反,有些頁面不需要通過HTTPS傳送,我們可以使用requiresInsecure()代替requiresSecure()方法。

防止跨站請求僞造(cross-site request forgery,CSRF)

如果一個站點欺騙用戶提交請求到其他服務器的話,就會發生CSRF攻擊。

Spring Security3.2開啓,默認會啓用CSRF防護。因爲我沒怎麼用到,所以細節就不多說了。

.csrf().disable()   //禁用CSRF防護

認證用戶

如果你使用最簡單的Spring Security配置的話,那麼就能無償得到一個登陸頁。實際上,在重寫configure(HttpSecurity)之前,我們都能使用一個簡單卻功能完備的登陸頁,但是一旦重寫了configure(HttpSecurity)方法,就失去了這個簡單的登錄頁面。

不過我們可以通過formLogin()方法把它找回來。

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
               .formLogin()           
               .and()                           
               .csrf().disable()  //禁用CSRF
                .authorizeRequests()         
                .antMatchers("/test","/tests").authenticated()
                .anyRequest().permitAll()
                ;
    }

添加自定義登錄頁面

上面可以看出,security給我們提供了默認的登錄頁面,當然,我們是可以自定義登錄頁面的,具體配置如下:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
               .formLogin()
               .loginPage("/login").defaultSuccessUrl("/success").failureUrl("/error")
               .and()
               .csrf().disable()
                .authorizeRequests()            
                .antMatchers("/test","/tests").authenticated()
                .anyRequest().permitAll()
                ;
    }


@RequestMapping("/login")
    public String login()
    {       
        return "login";
    }

注意:自定義的登陸頁也需要username和password輸入域!否則會一直認證失敗!!!!同時,loginPage()與自定義登陸頁的action訪問路徑是一樣的!!!

Spring Security使用Authentication獲取當前用戶信息

Spring Security使用一個Authentication對象來描述當前用戶的相關信息。SecurityContextHolder中持有的是當前用戶的SecurityContext,而SecurityContext持有的是代表當前用戶相關信息的Authentication的引用。這個Authentication對象不需要我們自己去創建,在與系統交互的過程中,Spring Security會自動爲我們創建相應的Authentication對象,然後賦值給當前的SecurityContext。但是往往我們需要在程序中獲取當前用戶的相關信息,比如最常見的是獲取當前登錄用戶的用戶名。在程序的任何地方,通過如下方式我們可以獲取到當前用戶的用戶名:

public String getCurrentUsername() {

      Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

      if (principal instanceof UserDetails) {

         return ((UserDetails) principal).getUsername();

      }

      if (principal instanceof Principal) {

         return ((Principal) principal).getName();

      }

      return String.valueOf(principal);

   }

通過Authentication.getPrincipal()可以獲取到代表當前用戶的信息,這個對象通常是UserDetails的實例。獲取當前用戶的用戶名是一種比較常見的需求,關於上述代碼其實Spring Security在Authentication中的實現類中已經爲我們做了相關實現,所以獲取當前用戶的用戶名最簡單的方式應當如下:

public String getCurrentUsername() {

      return SecurityContextHolder.getContext().getAuthentication().getName();

   }

啓用HTTP Basic認證

當在Web瀏覽器中使用時,它將向用戶彈出一個簡單的模擬對話框。

http
.httpBasic()
.and()
...

退出

退出功能是通過Servlet容器中的Filter實現的(默認情況下),這個Filter會攔截針對”/logout”的請求。因此,爲應用添加退出功能只需要添加以下的鏈接即可。

<a href="${pageContext.request.contextPath }/logout">退出</a>

在退出完成後,瀏覽器會重定向到“login?logout”,從而允許用戶進行再次登錄。如果你希望重定向到其他頁面可以

.logout().logoutSuccessUrl("/error")

logoutSuccessUrl(“/error”)表明在退出成功後,瀏覽器需要重定向到”/error”。我們還可以重寫默認的LogoutFilter攔截路徑。

.logout().logoutSuccessUrl("/error").logoutUrl("/tuichu")

前面說到LogoutFilter默認會攔截針對”/logout”的請求,在這裏我們通過logoutUrl(“/tuichu”)設置爲攔截”/tuichu”的請求。同時將退出的請求路徑更改爲如下所示

<a href="${pageContext.request.contextPath }/tuichu">退出</a>

保護視圖

當爲瀏覽器渲染html內容時,你可能希望視圖中能夠反映安全限制和相關的信息。或者你想根據用戶被授予了什麼權限,有條件的渲染特定的視圖內容。渲染視圖的兩個重要方案就是:JSP和Thymeleaf。

Spring Security本身提供了一個JSP標籤庫,而Thymeleaf通過特定的方言實現了與Spring Security的集成

Spring Security的JSP標籤庫

Spring Security的JSP標籤庫很小,就三個標籤。

爲了使用JSP標籤庫,我們需要在JSP文件中聲明它:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

訪問認證信息的頁面控制

藉助Spring Security的JSP標籤庫,所做的最簡單的一件事就是便利的訪問用戶的認證信息。這恰恰是 < security:authentication >能爲我們做的事情。例如:

hello<security:authentication property="principal.username" />

property用來標示用戶認證對象的一個屬性。可用的屬性取決於用戶認證的方式。

我們也可以將渲染屬性的值賦給一個變量,那隻需要在var屬性中指明變量的名字即可。

<security:authentication property="principal.username" var="name" />

這個變量默認是定義在頁面作用域內的,我們可以通過scope屬性來更改變量作用域。

<security:authentication property="principal.username" var="name"  scope="request" />

判斷用戶登錄

isAnonymous() 爲 true則表示未登錄,isAuthenticated()爲true則表示已登錄!

<!–匿名–>  
<security:authorize access="isAnonymous()">
    未登錄,點擊 <a>登錄</a>  
</security:authorize> 
<!–登錄–>  
<security:authorize access="isAuthenticated()">
    <h3>登錄成功!</h3>
</security:authorize>

條件性的渲染內容

有時候視圖上的一部分內容需要根據用戶被授予了什麼權限來確定是否渲染。Spring Security的< security:authorize >JSP標籤能夠根據用戶被授予的權限有條件的渲染頁面的部分內容。

hello<security:authentication property="principal.username" />
<security:authorize access="hasRole('user')">
<h1>有條件性的渲染的內容</h1>
</security:authorize>

access屬性被賦值給一個SpEL表達式,這個表達式的值確定< security:authorize >標籤內主體內的內容是否渲染。

剩餘問題,thymeleaf的整合使用。


近期整合了thymeleaf,使用oauth2結合security實現了帶點登錄,github地址:
https://github.com/producted/spring-learning/tree/master/zpk-oauth2-sso-demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章