当前位置: 代码网 > it编程>编程语言>Java > 基于Spring Security实现API Key认证的完整方案

基于Spring Security实现API Key认证的完整方案

2026年07月22日 Java 我要评论
实现类apikeyauthfilter 认证过滤器apikeyauthenticationtoken 认证令牌apikeyauthenticationprovider api认证鉴权securityc

实现类

  • apikeyauthfilter 认证过滤器
  • apikeyauthenticationtoken 认证令牌
  • apikeyauthenticationprovider api认证鉴权
  • securityconfig 安全配置类

apikeyauthfilter

方法概要
onceperrequestfilter 是 spring web 提供的一个抽象过滤器基类,核心作用是确保过滤器的 dofilterinternal 方法在一次http 请求的整个处理流程中只执行一次。
@component 自动注册为 spring bean。
注入 authenticationmanager

  • authenticationmanager 是 spring security 的 认证总入口;
  • 调用它的 authenticate() 方法会:
    • 遍历所有 authenticationprovider
    • 找到支持 apikeyauthenticationtoken 的 provider(即你的 apikeyauthenticationprovider);
    • 执行验证逻辑。
@component
public class apikeyauthfilter extends onceperrequestfilter {

    @autowired
    private authenticationmanager authenticationmanager; // 注入 authenticationmanager

    @override
    protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain filterchain)
            throws servletexception, ioexception {
        string apikey = request.getheader("x-api-key");
        // 只处理 /api/ 开头的接口(根据你的需求调整)
        if (apikey != null && request.getrequesturi().startswith("/api/")) {
            try {

                // 1. 创建未认证的 token
                apikeyauthenticationtoken authtoken = new apikeyauthenticationtoken(apikey);
                // 2. ⭐️ 关键:显式调用 authenticationmanager 进行认证
                authentication authenticated = authenticationmanager.authenticate(authtoken);
                // 3. 将认证成功的 token 放入 securitycontext
                securitycontextholder.getcontext().setauthentication(authenticated);

            } catch (authenticationexception e) {
                // 认证失败:清空上下文,并返回 401
                securitycontextholder.clearcontext();
                response.setstatus(httpservletresponse.sc_unauthorized);
                response.getwriter().write("invalid api key");
                return;
            }
        }

        filterchain.dofilter(request, response);
    }
}

apikeyauthenticationtoken

abstractauthenticationtoken 是 spring security 提供的认证令牌抽象类
继承实现用户登录以及令牌校验的操作,当 setauthenticated 等于true时直接放行

public class apikeyauthenticationtoken extends abstractauthenticationtoken {
    private final object principal;

    public apikeyauthenticationtoken(object principal) {
        // credentials 设为 null(api key 已用于认证,无需再存)
        super(null);
        this.principal = principal;
        // 初始为未认证(由 authenticationprovider 设置为 true)
        setauthenticated(false);
    }

    @override
    public object getcredentials() {
        return principal;
    }

    @override
    public object getprincipal() {
        return principal;
    }
}

apikeyauthenticationprovider

spring security 中实现 api key 认证的核心组件,它负责 验证客户端传入的 api key 是否合法,并生成已认证的安全上下文(authentication)。
核心关系:接口约定 + 方法实现(契约模式)
authenticationproviderspring security 定义的认证核心接口(契约),authenticate() 是这个接口强制要求实现的核心方法(契约内容)—— 简单说:

  • implements authenticationprovider:表示你的类「承诺遵守 spring security 的认证规则」;
  • authenticate():是你兑现这个承诺的「具体认证逻辑」(校验 api key、用户名密码等)。
@component
public class apikeyauthenticationprovider implements authenticationprovider {

    @autowired
    private isysapikeysservice sysapikeysservice;

	// 核心方法:执行具体的认证逻辑
    @override
    public authentication authenticate(authentication authentication) throws authenticationexception {
        string providedkey = (string) authentication.getcredentials();
        sysapikeys sysapikeys = sysapikeysservice.selectbyapikey(providedkey);
        if(sysapikeys != null){
            apikeyauthenticationtoken authenticatedtoken =
                    new apikeyauthenticationtoken(sysapikeys);
            return authenticatedtoken;
        }

        throw new badcredentialsexception("invalid api key");
    }

	// 辅助方法:判断当前 provider 是否支持处理某个类型的 token
    @override
    public boolean supports(class<?> authentication) {
        return apikeyauthenticationtoken.class.isassignablefrom(authentication);
    }
}

securityconfig

@enablemethodsecurity 注解(配合 @configuration)是为了启用方法级别的权限控制,比如通过 @preauthorize@secured 等注解限制接口访问
addfilterbefore()spring security 中用于自定义过滤器链顺序的核心方法,它的作用是:
在指定的内置(或已注册)filter 之前插入你自己的 filter。所以必须在 原有usernamepasswordauthenticationfilter 认证之前去先走apikeyauthfilter

// 添加 api filter
.addfilterbefore(apikeyauthfilter,usernamepasswordauthenticationfilter.class)

protected securityfilterchain filterchain(httpsecurity httpsecurity) throws exception
spring security 中配置 http 层面安全规则的核心方法,它的核心作用是通过 httpsecurity 对象定制请求的安全策略(如哪些请求需要认证、哪些放行、用什么方式认证、异常如何处理等)。下面我会从「核心作用、常用配置、实战示例、与方法级权限的区别」四个维度讲清楚这个方法的用处。

  • 这个方法的本质是构建一个 securityfilterchain 过滤器链,spring security 会将这个过滤器链应用到所有
  • http 请求上,实现: 控制哪些请求需要认证、哪些请求可以匿名访问(放行);
  • 定义认证方式(如 http basic、表单登录、jwt
    过滤器等);
  • 配置跨域(cors)、csrf 防护、会话管理; 定制认证失败、权限不足的响应(如返回 json 而非默认页面);
  • 整合自定义过滤器(如 jwt 校验过滤器)。

完整代码

/**
 * spring security配置
 * 
 * @author 
 */
@enablemethodsecurity(prepostenabled = true, securedenabled = true)
@configuration
public class securityconfig
{
    /**
     * 自定义用户认证逻辑
     */
    @autowired
    private userdetailsservice userdetailsservice;
    
    /**
     * 认证失败处理类
     */
    @autowired
    private authenticationentrypointimpl unauthorizedhandler;

    /**
     * 退出处理类
     */
    @autowired
    private logoutsuccesshandlerimpl logoutsuccesshandler;

    /**
     * token认证过滤器
     */
    @autowired
    private jwtauthenticationtokenfilter authenticationtokenfilter;

    @autowired
    private apikeyauthfilter apikeyauthfilter;
    
    /**
     * 跨域过滤器
     */
    @autowired
    private corsfilter corsfilter;

    /**
     * 允许匿名访问的地址
     */
    @autowired
    private permitallurlproperties permitallurl;

    @autowired
    apikeyauthenticationprovider apikeyauthenticationprovider;

    /**
     * 身份验证实现
     */
    @bean
    public authenticationmanager authenticationmanager()
    {
        daoauthenticationprovider daoauthenticationprovider = new daoauthenticationprovider();
        daoauthenticationprovider.setuserdetailsservice(userdetailsservice);
        daoauthenticationprovider.setpasswordencoder(bcryptpasswordencoder());

        return new providermanager(arrays.aslist(daoauthenticationprovider,
                apikeyauthenticationprovider));
    }

    /**
     * anyrequest          |   匹配所有请求路径
     * access              |   springel表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyall             |   用户不能访问
     * fullyauthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasanyauthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasanyrole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasauthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasipaddress        |   如果有参数,参数表示ip地址,如果用户ip和参数匹配,则可以访问
     * hasrole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitall           |   用户可以任意访问
     * rememberme          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @bean
    protected securityfilterchain filterchain(httpsecurity httpsecurity) throws exception
    {
        return httpsecurity
            // csrf禁用,因为不使用session
            .csrf(csrf -> csrf.disable())
            // 禁用http响应标头
            .headers((headerscustomizer) -> {
                headerscustomizer.cachecontrol(cache -> cache.disable()).frameoptions(options -> options.sameorigin());
            })
            // 认证失败处理类
            .exceptionhandling(exception -> exception.authenticationentrypoint(unauthorizedhandler))
            // 基于token,所以不需要session
            .sessionmanagement(session -> session.sessioncreationpolicy(sessioncreationpolicy.stateless))
            // 注解标记允许匿名访问的url
            .authorizehttprequests((requests) -> {
                permitallurl.geturls().foreach(url -> requests.antmatchers(url).permitall());
                // 对于登录login 注册register 验证码captchaimage 允许匿名访问
                requests.antmatchers("/login", "/register", "/captchaimage").permitall()
                    // 静态资源,可匿名访问
                    .antmatchers(httpmethod.get,
                            "/",
                            "/*.html",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js",
                            "/profile/**",
                            "/cadre/neo4j/**",
                            "/cadre/evaluation/rqcode/**")
                        .permitall()
                    .antmatchers(httpmethod.post,
                            "/cadre/cadre/home/recalculate")
                        .permitall()
                    .antmatchers(
                            "/swagger-ui.html",
                            "/swagger-resources/**",
                            "/webjars/**",
                            "/*/api-docs",
                            "/cadre/evaluation/qrcode/**",
                            "/cadre/evaluation/grade/rqcodescore/**",
                            "/druid/**")
                        .permitall()
                    // 除上面外的所有请求全部需要鉴权认证
                    .anyrequest().authenticated();
            })
            // 添加logout filter
            .logout(logout -> logout.logouturl("/logout").logoutsuccesshandler(logoutsuccesshandler))
            // 添加 api filter
            .addfilterbefore(apikeyauthfilter, usernamepasswordauthenticationfilter.class)
            // 添加jwt filter
            .addfilterbefore(authenticationtokenfilter, usernamepasswordauthenticationfilter.class)
            // 添加cors filter
            .addfilterbefore(corsfilter, jwtauthenticationtokenfilter.class)
            .addfilterbefore(corsfilter, logoutfilter.class)
            .build();
    }

    /**
     * 强散列哈希加密实现
     */
    @bean
    public bcryptpasswordencoder bcryptpasswordencoder()
    {
        return new bcryptpasswordencoder();
    }
}

以上就是基于spring security实现api key认证的完整方案的详细内容,更多关于spring security实现api key认证的资料请关注代码网其它相关文章!

(0)

相关文章:

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

发表评论

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