当前位置: 代码网 > it编程>编程语言>Java > SpringSecurity动态权限校验怎么实现?后端过滤器配置教程

SpringSecurity动态权限校验怎么实现?后端过滤器配置教程

2026年08月17日 Java 我要评论
后端springsecurity实现动态权限校验在框架defaultsecurityfilterchain源码内打断点可以找到springsecurity的过滤器链可以看见一个叫authorizati

后端springsecurity实现动态权限校验

在框架defaultsecurityfilterchain源码内打断点可以找到springsecurity的过滤器链可以看见一个叫authorizationfilter的过滤器

很明显这个叫authorizationmanager的应该是我们要找的玩意

直接去authorizationfilter内找这个类看他的源码可以发现check方法已经弃用,他推荐用的方法是authorize但这玩意也还是调用的check

@functionalinterface
public interface authorizationmanager<t> {

	/**
	 * determines if access should be granted for a specific authentication and object.
	 * @param authentication the {@link supplier} of the {@link authentication} to check
	 * @param object the {@link t} object to check
	 * @throws accessdeniedexception if access is not granted
	 */
	default void verify(supplier<authentication> authentication, t object) {
		authorizationdecision decision = check(authentication, object);
		if (decision != null && !decision.isgranted()) {
			throw new authorizationdeniedexception("access denied", decision);
		}
	}

	/**
	 * determines if access is granted for a specific authentication and object.
	 * @param authentication the {@link supplier} of the {@link authentication} to check
	 * @param object the {@link t} object to check
	 * @return an {@link authorizationdecision} or null if no decision could be made
	 * @deprecated please use {@link #authorize(supplier, object)} instead
	 */
	@nullable
	@deprecated
	authorizationdecision check(supplier<authentication> authentication, t object);

	/**
	 * determines if access is granted for a specific authentication and object.
	 * @param authentication the {@link supplier} of the {@link authentication} to
	 * authorize
	 * @param object the {@link t} object to authorize
	 * @return an {@link authorizationresult}
	 * @since 6.4
	 */
	@nullable
	default authorizationresult authorize(supplier<authentication> authentication, t object) {
		return check(authentication, object);
	}

继续往下面看

可以看见他是进行了校验然后返回了一个布尔值

	@override
	public authorizationdecision check(supplier<authentication> authentication, t object) {
		boolean granted = this.authorizationstrategy.isgranted(authentication.get());
		return new authorizationdecision(granted);
	}

代码实现

逻辑大概是通过传进来的接口路径然后匹配权限

@component
public class dynamicauthorizationmanager implements authorizationmanager<requestauthorizationcontext> {

    @resource
    private dynamicsecuritymetadatasource securitymetadatasource;

    @override
    public authorizationdecision check(supplier<authentication> authentication, requestauthorizationcontext context) {
        httpservletrequest request = context.getrequest();

        // 获取当前请求所需的权限
        string url = request.getrequesturi();
        string method = request.getmethod();
        filterinvocation fi = new filterinvocation(string.valueof(request), url, method);
        collection<configattribute> attributes = securitymetadatasource.getattributes(fi);

        // 没有配置权限要求,允许访问
        if (collectionutils.isempty(attributes)) {
            return new authorizationdecision(true);
        }

        // 获取当前用户认证信息
        authentication auth = authentication.get();


        if (auth == null || !auth.isauthenticated()) {
            return new authorizationdecision(false);
        }



        // 获取用户所拥有的权限
        set<string> userpermissions = auth.getauthorities().stream()
            .map(grantedauthority::getauthority)
            .collect(collectors.toset());

        // 判断是否有所需权限
        boolean haspermission = attributes.stream()
            .map(configattribute::getattribute)
            .anymatch(userpermissions::contains);

        return new authorizationdecision(haspermission);
    }
}

getallconfigattributes和supports我大概看了一下直接复制粘贴的框架的源码以后万一有用呢

@component
public class dynamicsecuritymetadatasource implements filterinvocationsecuritymetadatasource {

    @resource
    private tpmenuservice menuservice;

    private map<string, collection<configattribute>> configattributemap;

    @postconstruct
    public void loaddatasource() {
        configattributemap = new hashmap<>();
        list<tpmenu> menus = menuservice.list();
        configattributemap = menus.stream()
                .filter(menu -> stringutils.hastext(menu.getpath()) && stringutils.hastext(menu.getperms()))
                .collect(collectors.tomap(
                        tpmenu::getpath,
                        menu -> {
                            list<configattribute> attributes = new arraylist<>();
                            attributes.add(new securityconfig(menu.getperms()));
                            return attributes;
                        }
                ));
    }

    @override
    public collection<configattribute> getattributes(object object) throws illegalargumentexception {
        string requesturl = ((filterinvocation) object).getrequesturl();
        if (requesturl.contains("?")) {
            requesturl = requesturl.substring(0, requesturl.indexof("?"));
        }

        int count = stringutils.countoccurrencesof(requesturl, "/");
        if (count > 2) {
            requesturl = requesturl.replaceall("/[^/]+$", "");
        }
        for (map.entry<string, collection<configattribute>> entry : configattributemap.entryset()) {
            string pattern = entry.getkey();
            if (new antpathmatcher().match(pattern, requesturl)) {
                return entry.getvalue();
            }
        }
        return null;
    }

    @override
    public collection<configattribute> getallconfigattributes() {
        set<configattribute> allattributes = new hashset<>();
        configattributemap.values().foreach(allattributes::addall);
        return allattributes;
    }

    @override
    public boolean supports(class<?> clazz) {
        return filterinvocation.class.isassignablefrom(clazz);
    }

}

过滤器实现

然后记得security配置文件添加这个过滤器就ok了,配置文件可以看我另外一篇文章

@component
public class dynamicsecurityfilter extends onceperrequestfilter {

    @resource
    private dynamicsecuritymetadatasource securitymetadatasource;

    @resource
    private dynamicauthorizationmanager authorizationmanager;

    @resource
    private accessdeniedhandler accessdeniedhandler;

    @override
    protected void dofilterinternal(httpservletrequest request,
                                    httpservletresponse response,
                                    filterchain chain) throws servletexception, ioexception, ioexception {

        if (shouldnotfilter(request)) {
            chain.dofilter(request, response);
            return;
        }

        try {

            authentication authentication = securitycontextholder.getcontext().getauthentication();
            requestauthorizationcontext context = new requestauthorizationcontext(request);

            // 权限检查
            authorizationdecision check = authorizationmanager.check(
                    () -> authentication,
                    context
            );
            if (check.isgranted()) {
                chain.dofilter(request, response);
            } else {
                accessdeniedhandler.handle(request, response, new accessdeniedexception("权限不足"));
            }

        } catch (ioexception e) {
            throw new runtimeexception(e);
        } catch (servletexception e) {
            throw new runtimeexception(e);
        }
    }


    @override
    protected boolean shouldnotfilter(httpservletrequest request) {
   
        string path = request.getrequesturi();
        return whitelist.stream()
                .anymatch(pattern ->
                        pattern.endswith("/**")
                                ? path.startswith(pattern.substring(0, pattern.length() - 3))
                                : pattern.equals(path)
                );
    }
}

debug重启可以看见我的过滤器已经添加进去了

如果有需要还可以直接去看官方demo

https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/jwt/login/src/main

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com