@EnableGlobalMethodSecurity三方法詳解

 

 

 

@EnableGlobalMethodSecurity三方法詳解

要開啓Spring方法級安全,在添加了@Configuration註解的類上再添加@EnableGlobalMethodSecurity註解即可

 

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

其中註解@EnableGlobalMethodSecurity有幾個方法:

  • prePostEnabled 確定 前置註解[@PreAuthorize,@PostAuthorize,..] 是否啓用
  • securedEnabled 確定安全註解 [@Secured] 是否啓用
  • jsr250Enabled 確定 JSR-250註解 [@RolesAllowed..]是否啓用

在同一個應用程序中,可以啓用多個類型的註解,但是隻應該設置一個註解對於行爲類的接口或者類。如:

  • 一個程序啓用多個類型註解:

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true))
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        ...
    }
    
  • 但是隻應該設置一個註解對於行爲類的接口或者類

    public interface UserService {
      List<User> findAllUsers();
    
      @PreAuthorize("hasAnyRole('user')")
      void updateUser(User user);
    
        // 下面不能設置兩個註解,如果設置兩個,只有其中一個生效
        // @PreAuthorize("hasAnyRole('user')")
      @Secured({ "ROLE_user", "ROLE_admin" })
      void deleteUser();
    }
    

啓用securedEnabled

先啓用securedEnabled

 

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true))
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}

在調用的接口或方法使用如下:

 

public interface UserService {
    List<User> findAllUsers();
    
    @Secured({"ROLE_user"})
    void updateUser(User user);

    @Secured({"ROLE_admin", "ROLE_user1"})
    void deleteUser();
}

@Secured註解是用來定義業務方法的安全配置。在需要安全[角色/權限等]的方法上指定 @Secured,並且只有那些角色/權限的用戶纔可以調用該方法。

@Secured缺點(限制)就是不支持Spring EL表達式。不夠靈活。並且指定的角色必須以ROLE_開頭,不可省略。

在上面的例子中,updateUser 方法只能被擁有user權限的用戶調用。deleteUser 方法只能夠被擁有admin 或者user1 權限的用戶調用。而如果想要指定"AND"條件,即調用deleteUser方法需同時擁有ADMINDBA角色的用戶,@Secured便不能實現。

這時就需要使用prePostEnabled提供的註解@PreAuthorize/@PostAuthorize

啓用prePostEnabled

先啓用prePostEnabled

 

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}

在調用的接口或方法使用:

 

public interface UserService {
    List<User> findAllUsers();

    @PostAuthorize ("returnObject.type == authentication.name")
    User findById(int id);

    @PreAuthorize("hasRole('ADMIN')")
    void updateUser(User user);
    
    @PreAuthorize("hasRole('ADMIN') AND hasRole('DBA')")
    void deleteUser(int id);
}

該註解更適合方法級的安全,也支持Spring 表達式語言,提供了基於表達式的訪問控制。參見常見內置表達式瞭解支持表達式的完整列表

上面只使用到了一個註解@PreAuthorize,啓用prePostEnabled後,提供有四個註解:

  • @PreAuthorize 進入方法之前驗證授權。可以將登錄用戶的roles參數傳到方法中驗證。

    一些用法:

    // 只能user角色可以訪問
    @PreAuthorize ("hasAnyRole('user')")
    // user 角色或者 admin 角色都可訪問
    @PreAuthorize ("hasAnyRole('user') or hasAnyRole('admin')")
    // 同時擁有 user 和 admin 角色才能訪問
    @PreAuthorize ("hasAnyRole('user') and hasAnyRole('admin')")
    // 限制只能查詢 id 小於 10 的用戶
    @PreAuthorize("#id < 10")
    User findById(int id);
    
    // 只能查詢自己的信息
     @PreAuthorize("principal.username.equals(#username)")
    User find(String username);
    
    // 限制只能新增用戶名稱爲abc的用戶
    @PreAuthorize("#user.name.equals('abc')")
    void add(User user)
    
  • @PostAuthorize 該註解使用不多,在方法執行後再進行權限驗證。 適合驗證帶有返回值的權限。Spring EL 提供 返回對象能夠在表達式語言中獲取返回的對象returnObject。如:

    // 查詢到用戶信息後,再驗證用戶名是否和登錄用戶名一致
    @PostAuthorize("returnObject.name == authentication.name")
    @GetMapping("/get-user")
    public User getUser(String name){
        return userService.getUser(name);
    }
    // 驗證返回的數是否是偶數
    @PostAuthorize("returnObject % 2 == 0")
    public Integer test(){
        // ...
        return id;
    }
    
  • @PreFilter 對集合類型的參數執行過濾,移除結果爲false的元素

    // 指定過濾的參數,過濾偶數
    @PreFilter(filterTarget="ids", value="filterObject%2==0")
    public void delete(List<Integer> ids, List<String> username)
    
  • @PostFilter 對集合類型的返回值進行過濾,移除結果爲false的元素

    @PostFilter("filterObject.id%2==0")
    public List<User> findAll(){
        ...
        return userList;
    }
    

對於前面使用@Secured註解的缺點,現在使用@PreAuthorize/@PostAuthorize

 

public interface UserService {
    List<User> findAllUsers();

    @PostAuthorize ("returnObject.type == authentication.name")
    User findById(int id);

    @PreAuthorize("hasRole('ADMIN')")
    void updateUser(User user);
    
    @PreAuthorize("hasRole('ADMIN') AND hasRole('DBA')")
    void deleteUser(int id);
}

 

@preAuthorize 可使用 AND 和 or

表達式

描述

hasRole([role])

當前用戶是否擁有指定角色。

hasAnyRole([role1,role2])

多個角色是一個以逗號進行分隔的字符串。如果當前用戶擁有指定角色中的任意一個則返回true。

hasAuthority([auth])

等同於hasRole

hasAnyAuthority([auth1,auth2])

等同於hasAnyRole

Principle

代表當前用戶的principle對象

authentication

直接從SecurityContext獲取的當前Authentication對象

permitAll

總是返回true,表示允許所有的

denyAll

總是返回false,表示拒絕所有的

isAnonymous()

當前用戶是否是一個匿名用戶

isRememberMe()

表示當前用戶是否是通過Remember-Me自動登錄的

isAuthenticated()

表示當前用戶是否已經登錄認證成功了。

isFullyAuthenticated()

如果當前用戶既不是一個匿名用戶,同時又不是通過Remember-Me自動登錄的,則返回true。

 

 

 

啓用jsr250Enabled

jsr250Enabled註解比較簡單,只有

  • @DenyAll 拒絕所有訪問
  • @RolesAllowed({"USER", "ADMIN"}) 該方法只要具有"USER", "ADMIN"任意一種權限就可以訪問。這裏可以省略前綴ROLE_,實際的權限可能是ROLE_ADMIN
  • @PermitAll 允許所有訪問




轉至:https://www.jianshu.com/p/77b4835b6e8e
 

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