@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
方法需同時擁有ADMIN
和DBA
角色的用戶,@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