Featured image of post Spring Security(3)自定義登入頁面、控制角色權限登入

Spring Security(3)自定義登入頁面、控制角色權限登入

透過Spring Security自定義的角色來訪問我們的頁面,.authenticated()、.authorizeRequests() 超級重要,也將訪問頁面設定成前端設計好的頁面,實現真正的前後端分離,減少溝通成本

前言

在前一章Spring Security(2)使用Spring Security自定義使用者帳密、使用JDBC串接資料庫中,我們知道了如何透過Spring Security自定義的角色來訪問我們的頁面,接下來要做的是,如何設定哪些頁面不用登入跟可以訪問、哪些頁面有帳號密碼到才可以訪問,或是我們自定義的權限角色管理員、銷售員、就像賣場的賣家與用戶一樣,去控制這些頁面,也將訪問頁面設定成前端設計好的頁面,實現真正的前後端分離,減少溝通成本。

自定義登入頁面

要自定義頁面時,一樣到專門設定Spring Security中的一個類別WebSecurityConfigurerAdapter,在前幾章中我們用了SecurityConfig去繼承他,在自定義頁面時,我們要先實作方法configure(HttpSecurity http),一樣按右鍵->Generate->Override Methods,選擇configure(HttpSecurity http)。

在使用之前,值得注意的事情是SecurityConfig的antMatchers順序是有關係的,在每一個url執行時,程式如果返回了True下面就不會執行了,例如,如果anyRequest().permitAll()設定在其他規則比較嚴格條件的前面的話,Spring Security判斷符合條件,就不會往下在走,意思是最鬆的規則應該在放在最後面,越是嚴格的規則要放在前面。

下面範例提供了幾個較常用的功能,如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.formLogin() //自定義登入頁面
        .loginPage("/login.html")
        .loginProcessingUrl("/user/login") //設定登入頁面的url
      	.usernameParameter("uname")///登入表單form中使用者名稱輸入框input的name名,不修改的話預設是username
        .passwordParameter("pword")//form中密碼輸入框input的name名,不修改的話預設是password
        .defaultSuccessUrl("/home")    //成功登入之後導向
        .and().authorizeRequests() //表示要定義哪些被保護(.authenticated()),哪些不需要保護(authorizeRequests())
            .antMatchers("/","/hello").permitAll() //設置不管有無登入都可以直接訪問(permitAll)
        .anyRequest().authenticated() //這樣寫代表除了以上之外,其他都需要被保護
        .and().csrf().disable(); //關閉csrf防護
}

選擇角色權限進行控制的四種方法

在Spring Security中,我們可以針對用戶的角色進行訪問頁面的權限控制,例如說,設定某些頁面管理員才能訪問,有些頁面大家都可以訪問,或是自定義的角色等等,針對各種不同的情況,共有四種方法,返回都是True or False

四種方法比較表格

方法名稱 舉例 意思
hasAuthority(String authority) hasAuthority(“ADMIN”) ADMIN角色才可以訪問
hasAnyAuthority(String… authorities) hasAnyAuthority(“ADMIN,MANAGER”) 有ADMIN或MANAGER其中一個符合就可以訪問
hasRole(String role) hasRole(“Sale”) 角色權限全名ROLE_Sale才可以訪問
hasAnyRole(String… roles) hasAnyRole(“Sale,User”) 有角色權限全名ROLE_Sale或ROLE_User其中一者就可以訪問

hasAuthority()跟 hasRole()的雖然很像,其實都是設定角色是否可以訪問,但是如果查看一下hasRole()的來源碼,就可以知道差別

private static String hasRole(String role) {
    Assert.notNull(role, "role cannot be null");
    if (role.startsWith("ROLE_")) {
        throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
    } else {
        return "hasRole('ROLE_" + role + "')";
    }
}

以上我們可以發現,如果在程式裡面設計hasRole(“Sale”)代表在資料庫中,實際上角色全名為ROLE_Sale的才能進行登入,相同的hasAnyRole也是相同的道理。

超級重點.authenticated()、.authorizeRequests() ( 20220109更新)

authenticated()的作用,很後面才了解到,他的功能表示登入才可以訪問一切的網址,他其實是Spring Security最重要的一部份,如果沒有加上了他,網址就不會被攔截,可以想像成他就是關閉Spirng Security的一個方法,我也正是理解到了架構。

protected void configure(HttpSecurity http) throws Exception {
    http.formLogin() //自定義登入頁面
       //放有關於登入頁面的設定
        .and().authorizeRequests() 
  			//放有關於設定網址的問題,透過.permitAll()來表示不需要被保護的網址
       //或是其他特別的設定
        .anyRequest().authenticated() //再加上這個之後,就變成了除了上面設定以外的網址,其他都需要登入
        .and().csrf().disable(); //關閉防護
}

所以通常會這樣設計(上到下權限):

protected void configure(HttpSecurity http) throws Exception {
    http.formLogin() //自定義登入頁面
        .loginPage("/login.html")
        .loginProcessingUrl("/user/login") //設定登入頁面的url
        .defaultSuccessUrl("home")    //成功登入之後導向
        .and().authorizeRequests() //表示要定義哪些被保護,哪些不需要保護(不需要認證)
        		//先設定不用通過的     
      			.antMatchers("/","hello").permitAll()
            //角色權限配置篇
            .antMatchers("/manager").hasAuthority("ADMIN") 
            .antMatchers("/manager_2").hasAnyAuthority("ADMIN,MANAGER")
            .antMatchers("/sale_index").hasRole("Sale")
            .antMatchers("/role").hasAnyRole("Sale")
        .anyRequest().authenticated() //
        .and().csrf().disable(); //關閉防護
}

自定義403頁面

在配置類裡面進行設定沒有權限時返回的頁面403碼,html檔案放在resources/static就可以了

protected void configure(HttpSecurity http) throws Exception {
    http.exceptionHandling().accessDeniedPage("/403.html");
}

實作

接下來實作方面,我想結合對於資料庫的CRUD做複習,模擬在電商平台做開發時的情況,所以先這樣!

comments powered by Disqus