慢來比較快,虛心學技術
前一篇文章中,我們通過使用@Secured和@RolesAllowed兩個註解實現了簡單有效的基於角色的方法權限控制,但是有時候,我們並不是單純的針對角色身份進行限制就可以的,還需要使用某些邏輯進行限制,所以Spring Security提供了四個註解幫助我們更細粒地去控制方法訪問地權限,這些註解地參數都是SPEL表達式
使用這幾個註解之前,我們需要先將@EnableGlobalMethodSecurity()的prePostEnabled屬性設置爲true,如同前述,也可以同時使用securedEnabled和jsr250Enabled
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
首先測試使用addUser接口
@Override
public User addUser(User user) {
System.out.println("添加用戶");
return this.baseDao.save(user);
}
使用dba登錄,訪問/user/userForm,訪問用戶信息填寫頁面
提交表單,返回調用成功
- 使用@PreAuthorize實現方法前校驗,此處我們使用SPEL表達式限定addUser方法必須在訪問者具備ROLE_ADMIN身份,且傳入參數user的age屬性值必須大於50的情況下纔可以訪問
@Override
@PreAuthorize("hasRole('ROLE_ADMIN') AND #user.age>50")
public User addUser(User user) {
System.out.println("添加用戶");
return this.baseDao.save(user);
}
首先使用dba用戶進行訪問,訪問受限
再使用admin進行訪問,參數正確,允許訪問:
填寫錯誤參數,年齡age填寫爲40,訪問受限:
控制成功
- 使用@PostAuthorize實現方法後校驗,爲了方便校驗,Spring Security在SPEL中提供了returnObject代表方法返回對象,此處我們限制僅當方法返回的結果的userName屬性爲“admin”時纔可以放行
@Override
@PostAuthorize("returnObject.userName=='admin'")
public User addUser(User user) {
System.out.println("添加用戶");
return this.baseDao.save(user);
}
首先提交userName爲dba的用戶,訪問受限
提交userName爲admin的用戶,允許訪問
- 使用@PreFilter 和@PostFilter註解實現數據在執行方法前及執行方法後集合的過濾,Spring Scurity提供了filterObject對象指代目標攔截對象,在@PreFilter中使用時,其代表傳入列表參數,當傳入參數中存在多個列表時,我們可以使用filterTarget屬性指定需要過濾的目標參數的名稱;當在@PostFilter中使用時,其代表返回列表.
@Override
@PostFilter(value="filterObject.userName!=principal.username")//限制返回的列表中,只允許返回和當前登陸用戶名不同的user,即允許獲取非當前用戶
public List<User> getList() {
List<User> users = new ArrayList<>();
User user1 = new User("admin","123456",50);
User user2 = new User("dba","123456",51);
User user3 = new User("common","123456",52);
users.add(user1);
users.add(user2);
users.add(user3);
return users;
}
@Override
@PreFilter(filterTarget="users",value="filterObject.userName==principal.username")//限制進入方法的列表中,只能允許和當前登陸用戶名一致的user傳入,即只允許刪除當前用戶
public List<User> deleteList(List<User> users) {
return users;
}
編寫controller
@RequestMapping(value = {"/user/deleteUsers"})
public ModelAndView deleteUsers(){
ModelAndView model = new ModelAndView();
List<User> users = new ArrayList<>();
User user1 = new User("admin","123456",50);
User user2 = new User("dba","123456",50);
User user3 = new User("common","123456",50);
users.add(user1);
users.add(user2);
users.add(user3);
List<User> targetList = this.baseService.deleteList(users);
model.addObject("message","您刪除的用戶:");
model.addObject("users",targetList);
model.setViewName("showUserList");
return model;
}
@RequestMapping(value = {"/user/getUsers"})
public ModelAndView getUsers(){
ModelAndView model = new ModelAndView();
List<User> users = this.baseService.getList();
model.addObject("message","您獲取到的用戶");
model.addObject("users",users);
model.setViewName("showUserList");
return model;
}
編寫視圖:showUserList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>用戶信息列表</title>
</head>
<body>
<h2>${message}</h2>
<table style="border:1px solid orangered;">
<tr>
<th>用戶名</th>
<th>用戶密碼</th>
<th>用戶年齡</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td style="font-size: large">${user.userName}</td>
<td style="font-size: large">${user.password}</td>
<td style="font-size: large">${user.age}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
使用admin訪問/user/getUsers,結果獲取到非admin用戶信息
使用dba訪問/user/getUsers,結果獲取到非dba用戶信息
使用admin訪問/user/deleteUsers,結果僅刪除了自身