springboot security 權限控制 -- @PreAuthorize 的使用


1. 說明

security 鑒權方式常用的有兩種配置,1、配置文件中配置;2、使用注解標注;他們都是基於 acess 表達式,如果需要自定義邏輯的鑒權認證,只需要自定義 access 表達式即可。本文只選取注解的方式,來講解默認的 access 和自定義的 access 表達式

2.基於注解的使用

2.1 使用前提條件:

注解默認不可用,通過開啟注解:在配置類中開啟注解 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

  • @Secured:專門判斷用戶是否具有角色,可以寫在方法或類上,參數以 ROLE_ 開頭
  • @PreAuthorize\PostAuthorize: PreAuthorize 訪問的類或方法執行前判斷權限,而 PostAuthorize 在執行之后,Post 基本不用;允許與 ROLE_ 開頭。

2.2 基於默認的access表達式

在登錄的時候,需要將用戶權限返回給security;security才能實現權限控制功能;

具體步驟:
登錄時,實現 UserDetailService,重寫 loadUserByUsername(String userName)方法。根據 userName 來實現自己的業務邏輯返回 UserDetails 的實現類,需要自定義 User 類實現 UserDetails,比較重要的方法是 getAuthorities(),用來返回該用戶所擁有的權限

@Data
public class LoginUser implements UserDetails, Serializable {
    ...
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 根據自定義邏輯來返回用戶權限,如果用戶權限返回空或者和攔截路徑對應權限不同,驗證不通過
        if (!permissions.isEmpty()) {
            List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
            for (String temp : permissions) {
                GrantedAuthority au = new SimpleGrantedAuthority(temp);
                list.add(au);
            }
            return list;
        }
        return null;
    }
}

然后在需要權限控制的controller方法上,添加注解@PreAuthorize("hasAuthority('..*')");其中@PreAuthorize括號中就是access表達式。具體默認的有哪些請參考官網。

@RestController
@RequestMapping("test")
public class TestController {
    @Autowired
    private ISysUserService userService;
    @Autowired
    private PermissionService permissionService;

    @PreAuthorize("hasAuthority('*.*.*')")
    @RequestMapping("userList")
    public ResultVo queryUserList() {
        List<SysUser> list = userService.list();
        List<UserVo> result = list.stream().map(item -> permissionService.getUserInfo(item)).collect(Collectors.toList());
        return ResultVo.success(result);
    }
}

2.3 自定義access表達式

自定義權限認證業務邏輯,然后將該方法標注到注解上

package com.nanboone.framework.security.service;


import java.util.Set;

import com.nanboone.common.utils.ServletUtils;
import com.nanboone.framework.security.domain.LoginUser;
import com.nanboone.framework.token.JwtTokenUtils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * AuthorityPermissionService:自定義access表達式,鑒權驗證。
 * 可以將自定義的access添加到配置類中:http.anyRequest.access(aps.hasPermission(xxx,xxx));
 * 也可以直接使用注解@PreAuthorize:@PreAuthorize(aps.hasPermission(xxx));
 *
 * @Author: dangbo
 * @Date: 2021/5/20 10:12
 */
@Service("aps")
public class AuthorityPermissionService {

    @Autowired
    JwtTokenUtils jwtTokenUtils;

    public boolean hasPermission(String permissions) {
        if (StringUtils.isEmpty(permissions)) {
            return false;
        }
        // 用戶信息對象
        LoginUser loginUser = jwtTokenUtils.getLoginUser(ServletUtils.getRequest());
        if (loginUser == null || CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        Set<String> authorities = loginUser.getPermissions();
        for (String permission : permissions.split(",")) {
            if (StringUtils.isNotEmpty(permission) && hasPermissions(authorities, permission)) {
                return true;
            }
        }
        return false;
    }

    private boolean hasPermissions(Set<String> authorities, String permission) {
        return authorities.contains("*.*.*") || authorities.contains(permission.trim());
    }
}


@RestController
@RequestMapping("test")
public class TestController {
    @Autowired
    private ISysUserService userService;
    @Autowired
    private PermissionService permissionService;

    @PreAuthorize("@aps.hasPermission('*.*.*')")
    @RequestMapping("userList")
    public ResultVo queryUserList() {
        List<SysUser> list = userService.list();
        List<UserVo> result = list.stream().map(item -> permissionService.getUserInfo(item)).collect(Collectors.toList());
        return ResultVo.success(result);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM