实现类
apikeyauthfilter认证过滤器apikeyauthenticationtoken认证令牌apikeyauthenticationproviderapi认证鉴权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)。
核心关系:接口约定 + 方法实现(契约模式)authenticationprovider 是 spring 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认证的资料请关注代码网其它相关文章!
发表评论