原创

SpringSecurity自定义权限验证方式以及去除ROLE_前缀

自定义权限验证方式

e.g.以前的方式

@PostMapping("")
@Log(description = "添加菜单")
@PreAuthorize("hasAnyRole('admin','menu:add')")
public Menu create(@RequestBody @Valid Menu model) {
    return service.create(model);
}

自定义方式

@PostMapping("")
@Log(description = "添加菜单")
@PreAuthorize("@lzhpo.checkAnyOne('menu:add')")
public Menu create(@RequestBody @Valid Menu model) {
    return service.create(model);
}

权限验证配置LzhpoPermissionConfig

原理就是:先获取当前用户拥有的权限,再拿注解上的权限去比对用户拥有的权限,是否包含在其中,包含则返回true(有此注解上的权限),否则就返回false(没此注解上的权限)

import com.withive.system.security.AppUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

/**
 * 自定义权限认证方式,并且在验证的时候默认给拥有admin权限(ROLE_ADMIN)的用户放行
 *
 * @author Zhaopo Liu
 */
@Service(value = "lzhpo")
@Slf4j
public class LzhpoPermissionConfig extends AppUser {

    /**
     * 用户必须包含传入的所有权限
     * 
     * @param permissions
     * @return
     */
    public Boolean checkAll(String... permissions) {
        // 获取当前用户的所有权限
        List<String> lzhpoPermissions = getAuthorities();
        log.info("当前用户{}拥有的权限{}", getUsername(), lzhpoPermissions);
        // 判断当前用户的所有权限是否包含接口上定义的权限
        return lzhpoPermissions.contains("ROLE_ADMIN")
            || Arrays.stream(permissions).allMatch(lzhpoPermissions::contains);
    }

    /**
     * 用户只需包含传入的任一权限
     * 
     * @param permissions
     * @return
     */
    public Boolean checkAnyOne(String... permissions) {
        // 获取当前用户的所有权限
        List<String> lzhpoPermissions = getAuthorities();
        log.info("当前用户{}拥有的权限{}", getUsername(), lzhpoPermissions);
        // 判断当前用户的所有权限是否包含接口上定义的权限
        return lzhpoPermissions.contains("ROLE_ADMIN")
            || Arrays.stream(permissions).anyMatch(lzhpoPermissions::contains);
    }
}

SpringSecurity工具AppUser

import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

public class AppUser {

    public static Optional<SecurityUserDetails> getAppUserPrincipal() {
        return Optional.ofNullable(SecurityContextHolder.getContext()).map(SecurityContext::getAuthentication)
            .map((x) -> (SecurityUserDetails)x.getPrincipal());
    }

    public static Optional<SecurityUserDetails> getAppUserPrincipal(Authentication authentication) {
        return Optional.of(authentication).map((x) -> (SecurityUserDetails)x.getPrincipal());
    }

    protected String getUsername() {
        return getAppUserPrincipal().orElseThrow().getUsername();
    }

    protected String getName() {
        return getAppUserPrincipal().orElseThrow().getUsername();
    }

    protected String getUserId() {
        return getAppUserPrincipal().orElseThrow().getUserId();
    }

    protected List<String> getAuthorities() {
        return getAppUserPrincipal().stream()
            .flatMap(
                (Function<SecurityUserDetails, Stream<? extends GrantedAuthority>>)x -> x.getAuthorities().stream())
            .map(GrantedAuthority::getAuthority).collect(Collectors.toList());
    }
}

去除ROLE_前缀

在继承WebSecurityConfigurerAdapter的SpringSecurity配置类:

    @Override
    public void configure(WebSecurity webSecurity) {
        // ...

        /** 去除SpringSecurity中默认的权限ROLE_前缀 */
        webSecurity.expressionHandler(new DefaultWebSecurityExpressionHandler() {
            @Override
            protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
                WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
                // 去除默认的ROLE_前缀
                root.setDefaultRolePrefix("");
                return root;
            }
        });
    }

//    /**
//     * 去除SpringSecurity中默认的权限ROLE_前缀,{@link MyUserDetails#getAuthorities()}
//     *
//     * @author Zhaopo Liu
//     * @return
//     */
//    @Bean
//    GrantedAuthorityDefaults grantedAuthorityDefaults() {
//        return new GrantedAuthorityDefaults("");
//    }

在实现UserDetails的类就可以不用加上ROLE_前缀了。

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> authorities = new LinkedList<>();
    // 添加角色权限
    for (Role role : user.getRoles()) {
        //            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getCode()));
        authorities.add(new SimpleGrantedAuthority(role.getCode()));
        // 添加菜单权限
        for (Menu menu : role.getMenus()) {
            if (menu.getIsEnable() && !menu.getIsDelete()) {
                //                    authorities.add(new SimpleGrantedAuthority("ROLE_" + menu.getCode()));
                authorities.add(new SimpleGrantedAuthority(menu.getCode()));
            }
        }
    }

    return authorities;
}
正文到此结束
本文目录