Java:Springboot + jwt 实现带权限的认证(不使用spring security)
本文目录
认证的技术栈(持续更新中)
- 什么是 Token(令牌)?
- 数字签名signature
- jwt 的基本原理介绍
- 自定义一个jwt 工具类,并用接口测试
- Springboot + jwt 实现带权限的认证(不使用spring security)
前言
前几天,diy 了一个jwt工具类,今天使用成熟的 jjwt-api 编写一个不使用spring security 的轻量级 带权限的认证。
我们在带权限认证中,将 认证放在 过滤器中, 将权限放在 拦截器 中,为什么如此安排,可以看《过滤器和拦截器的区别》。
开发环境: spring boot 3.5.4 、 java 17 。
项目结构

第一步:maven的 pom.xml 中添加 jwt 依赖包
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- 实现模块(必须包含,否则无具体逻辑) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- 可选:JSON 处理模块(若用默认序列化需添加) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
第二步:新建配置文件,并新建配置文件属性对应的类
1. 新建 application.yml 配置文件
文件中只有两大类配置
-
login.jwt:jwt 认证的配置,包括令牌前缀、请求头名称、令牌的过期时间、加密算法的公钥和私钥 -
api.permission: 接口的权限配置,一共分为三组:– path:
"/api/admin/**", 只有 ADMIN 权限可访问的路径
– path:"/api/user/**", ADMIN、USER权限 都可访问的路径
– path:"/api/public/**"ANONYMOUS 权限都可以访问,即所有权限都可以访问的路径,
login:
## 认证配置
jwt:
# 过期时间(单位:秒)
expiration: 3600
# 令牌前缀
token-prefix: Bearer
# 请求头名称
header: Authorization
# RSA公钥, PEM格式
public-key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq0n+iYbJx+F9CQ5pUCvq
DqULv1kB5n4EfRi8HTDtRbsggQWG7UzXMHKuCNgE3SV9ysDaQKgOJEXPcfSrIJzZ
fe7dp8+LH3wRxIT7FKc7yegLe6VtAVSSx3gdP5Zs/J0QrrgHq/Gd/iIOglxUjrxt
j4AxgDCBkHIKWnxVYXDEcGIiuN9h013ocyU0+i/g5+nkMaQsFotlvy/+Xb1p+VjB
Sf2lVB3gC9HPYWepCGwxnp2wbACZzrQvvUdwqEjUnzUmjRUjAZlLBtsOQC8uYT3u
7UL2oiNakS9blxJTc20fGM2YueBhxw7IMpX7NSO4yBQpAMTYjXvTW7iNFgpaWzC1
xQIDAQAB
-----END PUBLIC KEY-----
# RSA私钥
private-key: |
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrSf6JhsnH4X0J
DmlQK+oOpQu/WQHmfgR9GLwdMO1FuyCBBYbtTNcwcq4I2ATdJX3KwNpAqA4kRc9x
9KsgnNl97t2nz4sffBHEhPsUpzvJ6At7pW0BVJLHeB0/lmz8nRCuuAer8Z3+Ig6C
XFSOvG2PgDGAMIGQcgpafFVhcMRwYiK432HTXehzJTT6L+Dn6eQxpCwWi2W/L/5d
vWn5WMFJ/aVUHeAL0c9hZ6kIbDGenbBsAJnOtC+9R3CoSNSfNSaNFSMBmUsG2w5A
Ly5hPe7tQvaiI1qRL1uXElNzbR8YzZi54GHHDsgylfs1I7jIFCkAxNiNe9NbuI0W
ClpbMLXFAgMBAAECggEAdD5XG4X50khYzpiVJ+9lfGLNwiHphD7pVOxAXZ8ipzwD
JwxVMR4Au8RYD3BqfJpA8CRI+bATSNKHodJlgFBx2WEN1CCpTcipVjDZJH8JuFBd
2p+9hjWbFvuQ/eJcPGNrOudxbWMf0aPTLOz0BZoi0EwzS8efZiO+mwHd/67D4W/b
BsZtpG6sk1+9nVlJMPiQSHwBN+fAbBAc74/ut38tBUV6Vus2Oz+9Z0pCTWgI6vwW
DvoNXZoEhiU4iCf3nltkfuhr++boYabsZdMcAg5AxdNPa1A40Kys8Uu44ta7xCmH
Jflj3AItYUTtzEWCkkiR0AiGkG7VDzUdtXanTRiRAQKBgQDiMUiu/IILHKNeQXpJ
EMHgslTcj4ktfoAYJbCHETA1LBoRl7Wh7UGEp+X8k8Urlg9DoEYapQCTLcCCJpFR
RmrI9meqaeidcm+OByi6dqUPLjcI2kEGeN3SDehqT/y1269XAdWIxB9n3k3qmpNK
pigK4XXU6ThGWWfOHg8jxCxb1QKBgQDB3IO5hdBS7lLF0N4TvaLQijirKXsjWSh9
zv0IcE8zeR4JUMM/n/H6PVGjHCi5tzU/lS9RGDUJzpQtiZxwRRaC63IHxleqvqBU
Dx//ngHqJwtBBOv/aKmX6gsdklK922X6t4J9tvH+NKI7GTilzg1XGjT7iCTaCNGO
23+7pSGaMQKBgQCc/hXzlkDwU3U0Y3/rnJzkRwJNf7Z3hBiGKgqnBJAQJ8cENOcV
N6ZE23/uWeX9BY8coe5maeXHQXcfHoO4BIbzasqy5gVU2muBCYkEOnr/2VTLaSi+
xD85nvuUZmYBFzRQ0G4UGgOuRQaRca4PntmmC6yMFT9A3KcG0agya+NZ7QKBgAk2
GyQzkYR/QnuXwxWZCyVxi+PGIs25LM1dinReMcU2WhEDP2PEi9DiHQDtE5pPdD5D
Lm5iAhMnN686PK6w+bLa0R5BdGTujduwpEqXDWw80rISM8x9AqHvQvvyue+/fwb8
tTyX9sOnaJX6StDGC6g53I6fF3EsvhhVoaoe3IvhAoGBANatqF2y2E49cSqxKoC5
FDGCLOte7H3lzokjjdbnL49fz6IXjzgI1/A57fQve6yyl9Cm028Vxamfb/FAabv0
2yrjmEBEH8sBPqP4t/Gr8Dm49EZXsRoqe90++SBVtCcAGgXubUZkm2KFhBleZZCn
E5/QOqCAtHOkHykLnlBLIT69
-----END PRIVATE KEY-----
# 接口权限配置
api:
permissions:
# 功能:不同的角色,可以访问的路径,如 ADMIN 可以访问 /api/admin/** 和 /api/user/** 两种路径
- path: "/api/admin/**"
roles: ADMIN
- path: "/api/user/**"
roles: USER,ADMIN
- path: "/api/public/**"
roles: ANONYMOUS
## 上面的格式会被解析成:
# {
# "api": {
# "permissions": [
# { "path": "/api/admin/**", "roles": "ADMIN" },
# { "path": "/api/user/**", "roles": "USER,ADMIN" },
# { "path": "/api/public/**", "roles": "ANONYMOUS" }
# ]
# }
# }
2. 新建 jwtProperties 类
这个类用于保存application.yml中的 login.jwt 中的各个属性,主要包括令牌前缀、请求头名称、令牌的过期时间、加密算法的公钥和私钥各个属性
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "login.jwt")
public class JwtProperties {
//公钥
private String publicKey;
//私钥
private String privateKey;
// 过期时间
private long expiration;
// token前缀,默认 Bearer
private String tokenPrefix;
// token 的key名,默认为Authorization
private String header;
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
public long getExpiration() {
return expiration;
}
public void setExpiration(long expiration) {
this.expiration = expiration;
}
public String getTokenPrefix() {
return tokenPrefix;
}
public void setTokenPrefix(String tokenPrefix) {
this.tokenPrefix = tokenPrefix;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
}
3. 新建 ApiPermssionProperties 类
这个类主要是获取 application.yml 中权限的属性,包括不同的角色所能访问的路径:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* API的权限属性,从application.yaml中读取
*/
@Component
@ConfigurationProperties(prefix = "api")
public class ApiPermissionProperties {
private List<Permission> permissions;
// 静态内部类:存储单个路径-角色映射
public static class Permission {
private String path;
private String roles;
// getter和setter
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
}
// 外部类的getter和setter
public List<Permission> getPermissions() {
return permissions;
}
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
}
第三步:新建工具类
1. 新建RsaUtils工具类
在本项目中,jwt 签名的加密算法使用的是 RSA 算法,所以RsaUtils的作用,就是将从configuation.yml中获取的 私钥和公钥 的字符串形式,转换成 具体的实例,以供 JwtUtils 类调用
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RsaUtils {
/**
* 从字符串中加载公钥
*/
public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
// 去除换行和BEGIN/END标记
publicKeyStr = publicKeyStr.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}
/**
* 从字符串中加载私钥
*/
public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception {
// 去除换行和BEGIN/END标记
privateKeyStr = privateKeyStr.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}
}
2. 新建JwtUtils工具类
JwtUtils 用于 生成 jwt 令牌、验证 jwt 令牌、从令牌中获取用户信息,和从来令牌中获取角色。
import com.example.spring_jwt2.config.JwtProperties;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtils {
final private JwtProperties jwtProperties;
private PrivateKey privateKey;
private PublicKey publicKey;
@Autowired // 这个@Autowired,就是提醒JwtUtils再执行方法之前,先将构造函数的JwtProperties jwtProperties注入
// 初始化密钥
public JwtUtils(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
try {
this.privateKey = RsaUtils.getPrivateKey(jwtProperties.getPrivateKey());
this.publicKey = RsaUtils.getPublicKey(jwtProperties.getPublicKey());
}catch (Exception ex){
String s =ex.toString();
}
}
/**
* 生成JWT令牌
* @param username 用户名
* @param roles 角色列表
* @return JWT令牌
*/
public String generateToken(String username, String... roles) {
// 设置过期时间
Date expirationDate = new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 1000);
// 设置自定义声明
Map<String, Object> claims = new HashMap<>();
claims.put("roles", roles);
// 生成令牌
return Jwts.builder()
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(expirationDate)
.signWith(privateKey, SignatureAlgorithm.RS256)
.compact();
}
/**
* 解析JWT令牌,获取声明
*/
public Claims parseClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(token)
.getBody();
}
/**
* 验证JWT令牌是否有效
*/
public boolean validateToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
// 令牌无效(过期、签名错误等)
return false;
}
}
/**
* 从令牌中获取用户名
*/
public String getUsernameFromToken(String token) {
return parseClaims(token).getSubject();
}
/**
* 从令牌中获取角色列表
*/
@SuppressWarnings("unchecked")
public String[] getRolesFromToken(String token) {
Claims claims = parseClaims(token);
return ((java.util.List<String>) claims.get("roles"))
.toArray(new String[0]);
}
}
第四步:过滤器和拦截器的编写和配置
1. 新建 JwtAuthFilter类, jwt认证的过滤器
这个是一个过滤器,jwt的认证就是在这个过滤器中,当认证成功,就进入下一步的拦截器;认证失败,则立即返回客户端失败信息。
import io.jsonwebtoken.Claims;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.PrintWriter;
/**
* JWT认证的过滤器
* 负责验证令牌有效性并解析用户信息
*/
@Component
@Order(1)
public class JwtAuthFilter implements Filter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private JwtProperties jwtProperties;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json;charset=UTF-8");
// 1. 从请求头获取令牌,从httpRequest 中获取 完整的token
String token = httpRequest.getHeader(jwtProperties.getHeader());
// 2. 处理令牌前缀,即将获取的令牌的前缀去掉
if (token != null && token.startsWith(jwtProperties.getTokenPrefix())) {
token = token.substring(jwtProperties.getTokenPrefix().length()).trim();
}
// 3. 验证令牌
if (token == null || !jwtUtils.validateToken(token)) { // 如果令牌为空,或者验证失败
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter out = httpResponse.getWriter();
out.write("{\"code\":401,\"message\":\"认证失败:无效的令牌\"}");
out.flush();
out.close();
return;
}
// 4. 解析令牌,获取用户信息 (用户名和角色),如果没有权限的需求,可以省略 第4、5 两个步骤,也不用写拦截器
Claims claims = jwtUtils.parseClaims(token);
String username = claims.getSubject();
String[] roles = jwtUtils.getRolesFromToken(token);
// 5. 将用户信息存入请求属性,供后面的拦截器使用
httpRequest.setAttribute("currentUsername", username);
httpRequest.setAttribute("currentRoles", roles);
// 6. 放行请求
chain.doFilter(request, response);
}
}
2. 新建 PermissionInterceptor 类, 权限拦截器
权限拦截器,根据在认证过滤器中 获取的 角色,检查角色是否有权限 访问 请求的路径。在这里是否有一个疑问,凭什么认为在 认证过滤器中的角色 就是正确的? 因为我们的 jwt 认证 本来就有防篡改的功能。所以这里放心的使用从过滤器中获取的角色,它如果被篡改了, 就过不了前面的认证了。
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.List;
/**
* 权限拦截器
* 负责验证用户是否有权限访问特定接口
*/
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Autowired
private ApiPermissionProperties apiPermissionProperties;
/**
* 在处理前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
response.setContentType("application/json;charset=UTF-8");
// 1. 获取当前请求路径
String requestUri = request.getRequestURI();
// 2. 获取用户角色
String[] currentRoles = (String[]) request.getAttribute("currentRoles");
if (currentRoles == null) { // 没有获取到角色
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
out.write("{\"code\":403,\"message\":\"权限不足:未获取用户角色信息\"}");
out.flush();
out.close();
return false;
}
// 3. 检查权限配置
// Map<String, String> permissions = apiPermissionProperties.getPermissions();
List<ApiPermissionProperties.Permission> permissions = apiPermissionProperties.getPermissions();
// for (ApiPermissionProperties.Permission perm : permissions) {
// String path = perm.getPath(); // 此处能正确获取带斜杠的路径,如"/api/admin/**"
// String roles = perm.getRoles();
// // 业务逻辑处理...
// }
boolean hasPermission = false;
// 4. 匹配接口路径并检查权限
for (ApiPermissionProperties.Permission perm : permissions) {
String pattern = perm.getPath();
String allowedRolesStr = perm.getRoles();
// 将Ant风格的路径模式转换为正则表达式
String regex = pattern.replace("/**", "/.*")
.replace("*", "[^/]*")
.replace("?", ".");
if (Pattern.matches(regex, requestUri)) { // 判断 请求的 uri 是否能在 application.yml 文件中找到已经配置的路径
// 检查用户角色是否在允许的角色列表中
String[] allowedRoles = allowedRolesStr.split(",");
for (String role : currentRoles) { // 循环请求中的角色,
if (Arrays.asList(allowedRoles).contains(role)) { // 如果在当前路径中可以找到此角色,则说明有权限
hasPermission = true;
break;
}
}
break;
}
}
// 5. 权限校验结果处理
if (!hasPermission) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
out.write("{\"code\":403,\"message\":\"权限不足:没有访问该接口的权限\"}");
out.flush();
out.close();
return false;
}
// 6. 权限校验通过,放行
return true;
}
}
3. 新建 WebConfig, 配置过滤器和拦截器
将刚刚新建的过滤器和 拦截器配置到程序中,这样每次请求,就必须要经过滤器和拦截器了。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private PermissionInterceptor permissionInterceptor;
/**
* 过滤器
* @param myFilter
* @return
*/
@Bean
public FilterRegistrationBean<JwtAuthFilter> myFilterRegistration(JwtAuthFilter myFilter) {
FilterRegistrationBean<JwtAuthFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(myFilter);
// 明确指定需要拦截的路径
registration.addUrlPatterns("/api/admin/*", "/api/user/*");
// 可选:指定需要排除的路径(如果有)
registration.addInitParameter("exclusions", "/api/public/*");
return registration;
}
/**
* 拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册权限拦截器,拦截需要权限验证的接口
registry.addInterceptor(permissionInterceptor)
.addPathPatterns("/api/admin/**", "/api/user/**") //添加拦截的路径
.excludePathPatterns("/api/public/**"); // 放行的路径
}
}
第五步:编写接口
1. 新建AuthController类, 授权接口
这里就只包含一个登录接口,登录成功,就签发一个token,即通过Authorization(授权)了。这里我们只用于测试,所以默认都是登录成功的,实际开发环境中,要将账号密码和服务器中的账号密码 比对的。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 认证控制器
* 提供登录接口,用于获取JWT令牌
*/
@RestController
public class AuthController {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private JwtProperties jwtProperties;
/**
* 登录接口,用于获取JWT令牌
* 实际项目中应该验证用户名密码的正确性
*/
@PostMapping("/api/public/login")
public Map<String, Object> login(
@RequestParam String username,
@RequestParam String password) {
// 这里简化处理,实际项目中应该从数据库中读取用户信息, 验证用户名密码,验证成功才能发放令牌。不成功,提示登录失败。
// 为了测试,假设不同用户有不同角色
String[] roles;
if ("admin".equals(username)) {
roles = new String[]{"ADMIN", "USER"};
} else if ("user".equals(username)) {
roles = new String[]{"USER"};
} else {
roles = new String[]{"GUEST"};
}
// 生成JWT令牌
String token = jwtUtils.generateToken(username, roles);
// 构建响应
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "登录成功");
response.put("token", jwtProperties.getTokenPrefix() + " " + token);
response.put("username", username);
response.put("roles", roles);
return response;
}
}
2. 新建TestController类,测试接口(可以愉快的测试了)
定义了三个不同权限的接口。
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 测试控制器
* 提供不同权限要求的接口用于测试
*/
@RestController
public class TestController {
/**
* 公开接口,不需要认证
*/
@GetMapping("/api/public/info")
public Map<String, Object> publicInfo() {
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "这是公开信息,任何人都可以访问");
return response;
}
/**
* 用户接口,需要USER或ADMIN角色
*/
@GetMapping("/api/user/profile")
public Map<String, Object> userProfile(HttpServletRequest request) {
String username = (String) request.getAttribute("currentUsername");
String[] roles = (String[]) request.getAttribute("currentRoles");
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "这是用户个人信息");
response.put("username", username);
response.put("roles", roles);
return response;
}
/**
* 管理员接口,需要ADMIN角色
*/
@GetMapping("/api/admin/dashboard")
public Map<String, Object> adminDashboard(HttpServletRequest request) {
String username = (String) request.getAttribute("currentUsername");
String[] roles = (String[]) request.getAttribute("currentRoles");
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "这是管理员控制台");
response.put("username", username);
response.put("roles", roles);
return response;
}
}
现在就可以愉快的测试了。
测试接口
将程序运行,使用 Thunder client 或postman 工具测试 接口
1. 先测试 /api/public/info ,公共接口,
这是所有人都可以访问,所以应该不需要登录。

正常返回没问题。
2. 测试 api/user/profile
-
我们先直接请求,不带token 试试看

成功的将其过滤了。 -
先使用user登录,获取 token ,再使用token 请求一次

登录,成功返回 token,并且此时的 token 拥有 USER 的权限了,带着token再一次请求.

OK ,可以访问。
3. 测试 api/admin/dashboard
我们用刚刚的token 能否 成功请求 api/admin/dashboard 呢?这个可是需要 ADMIN角色的权限的。

提示权限不足,使用admin 登录,获取ADMIN 的角色

这一次返回的token 是 ADMIN 的角色了,使用新的 token 请求一次

这一次没问题了。
后续文章,将学习如何使用 Spring security 实现 带权限的安全认证。
更多推荐
所有评论(0)