《Spring實戰》-第十四章:保護方法(Security)(2)-使用表達式增強方法保護

慢來比較快,虛心學技術

前一篇文章中,我們通過使用@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,結果僅刪除了自身

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