1. spring security 集成 jwt 概述
json web token(jwt)是一种用于在网络应用间安全传递信息的开放标准(rfc 7519)。spring security 集成 jwt 可以实现无状态的身份验证和授权机制,在电商系统中常用于用户登录认证和权限管理。
2. 搭建 jwt 认证工程
2.1 依赖添加
在 pom.xml 中添加 spring security、spring boot web、jjwt 等必要依赖。
<dependencies>
<!-- spring boot web -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<!-- spring security -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-security</artifactid>
</dependency>
<!-- jjwt -->
<dependency>
<groupid>io.jsonwebtoken</groupid>
<artifactid>jjwt</artifactid>
<version>0.9.1</version>
</dependency>
<!-- redis -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>
</dependencies>2.2 配置 spring security
创建 spring security 配置类,配置认证和授权规则。
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.security.config.annotation.web.builders.httpsecurity;
import org.springframework.security.config.annotation.web.configuration.enablewebsecurity;
import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter;
import org.springframework.security.config.http.sessioncreationpolicy;
import org.springframework.security.web.authentication.usernamepasswordauthenticationfilter;
@configuration
@enablewebsecurity
public class securityconfig extends websecurityconfigureradapter {
private final jwtauthenticationfilter jwtauthenticationfilter;
public securityconfig(jwtauthenticationfilter jwtauthenticationfilter) {
this.jwtauthenticationfilter = jwtauthenticationfilter;
}
@override
protected void configure(httpsecurity http) throws exception {
http
.csrf().disable()
.sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless)
.and()
.authorizerequests()
.antmatchers("/api/auth/login").permitall()
.anyrequest().authenticated()
.and()
.addfilterbefore(jwtauthenticationfilter, usernamepasswordauthenticationfilter.class);
}
}
3. 使用 jwt 认证
3.1 生成 jwt
创建 jwt 工具类,用于生成和解析 jwt。
import io.jsonwebtoken.claims;
import io.jsonwebtoken.jwts;
import io.jsonwebtoken.signaturealgorithm;
import org.springframework.beans.factory.annotation.value;
import org.springframework.stereotype.component;
import java.util.date;
@component
public class jwtutils {
@value("${jwt.secret}")
private string secret;
@value("${jwt.expirationms}")
private int expirationms;
public string generatejwttoken(string username) {
return jwts.builder()
.setsubject(username)
.setissuedat(new date())
.setexpiration(new date((new date()).gettime() + expirationms))
.signwith(signaturealgorithm.hs512, secret)
.compact();
}
public string getusernamefromjwttoken(string token) {
return jwts.parser().setsigningkey(secret).parseclaimsjws(token).getbody().getsubject();
}
public boolean validatejwttoken(string authtoken) {
try {
jwts.parser().setsigningkey(secret).parseclaimsjws(authtoken);
return true;
} catch (exception e) {
return false;
}
}
}
3.2 认证过滤器
创建 jwt 认证过滤器,用于拦截请求并验证 jwt。
import io.jsonwebtoken.expiredjwtexception;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.security.authentication.usernamepasswordauthenticationtoken;
import org.springframework.security.core.context.securitycontextholder;
import org.springframework.security.core.userdetails.userdetails;
import org.springframework.security.core.userdetails.userdetailsservice;
import org.springframework.security.web.authentication.webauthenticationdetailssource;
import org.springframework.stereotype.component;
import org.springframework.web.filter.onceperrequestfilter;
import javax.servlet.filterchain;
import javax.servlet.servletexception;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import java.io.ioexception;
@component
public class jwtauthenticationfilter extends onceperrequestfilter {
@autowired
private jwtutils jwtutils;
@autowired
private userdetailsservice userdetailsservice;
@override
protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain filterchain)
throws servletexception, ioexception {
try {
string jwt = parsejwt(request);
if (jwt != null && jwtutils.validatejwttoken(jwt)) {
string username = jwtutils.getusernamefromjwttoken(jwt);
userdetails userdetails = userdetailsservice.loaduserbyusername(username);
usernamepasswordauthenticationtoken authentication = new usernamepasswordauthenticationtoken(
userdetails, null, userdetails.getauthorities());
authentication.setdetails(new webauthenticationdetailssource().builddetails(request));
securitycontextholder.getcontext().setauthentication(authentication);
}
} catch (expiredjwtexception e) {
// 处理 jwt 过期异常
}
filterchain.dofilter(request, response);
}
private string parsejwt(httpservletrequest request) {
string headerauth = request.getheader("authorization");
if (headerauth != null && headerauth.startswith("bearer ")) {
return headerauth.substring(7);
}
return null;
}
}
4. 使用 redis 解决退出时 jwt 不能过期问题
4.1 redis 配置和启动
在 application.properties 中配置 redis 连接信息。
spring.redis.host=localhost spring.redis.port=6379
确保 redis 服务已启动,可以使用 docker 快速启动 redis 容器。
docker run -p 6379:6379 redis
4.2 将 jwt 放到 redis 中
创建 redis 工具类,用于操作 redis 存储 jwt。
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.stereotype.component;
import java.util.concurrent.timeunit;
@component
public class redisutils {
@autowired
private redistemplate<string, string> redistemplate;
public void set(string key, string value, long timeout, timeunit unit) {
redistemplate.opsforvalue().set(key, value, timeout, unit);
}
public boolean haskey(string key) {
return redistemplate.haskey(key);
}
public void delete(string key) {
redistemplate.delete(key);
}
}
4.3 解决退出问题
在用户退出时,将 jwt 存入 redis 黑名单,后续验证时检查 jwt 是否在黑名单中。
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.requestheader;
import org.springframework.web.bind.annotation.restcontroller;
import java.util.concurrent.timeunit;
@restcontroller
public class authcontroller {
@autowired
private jwtutils jwtutils;
@autowired
private redisutils redisutils;
@postmapping("/api/auth/logout")
public string logout(@requestheader("authorization") string authorizationheader) {
string jwt = authorizationheader.substring(7);
long expiration = jwtutils.getexpirationdatefromjwttoken(jwt).gettime() - system.currenttimemillis();
redisutils.set(jwt, "blacklisted", expiration, timeunit.milliseconds);
return "logged out successfully";
}
}
5. 示例总结
- 工程搭建:添加必要依赖,配置 spring security 实现基本的认证和授权规则。
- jwt 认证:使用 jjwt 库生成和解析 jwt,创建认证过滤器拦截请求并验证 jwt。
- redis 集成:配置 redis 连接信息,使用 redis 存储 jwt 黑名单,解决 jwt 退出不能过期的问题。
以上就是在spring security中集成jwt实现无状态认证的详细内容,更多关于spring security集成jwt无状态认证的资料请关注代码网其它相关文章!
发表评论