SpringSecurity配置 2
SpringSecurity配置 2
目前的现状,虽然是有了登录认证的接口,但是登录完成后,当我们访问受保护的接口时,即使将 Token 令牌携带与请求一起发送,依然是无法请求成功。另外,提示信息如下图所示,非常不友好,和之前定义好的统一返参格式也不一致。
1. 新建 Token 校验过滤器
首先,我们在 weblog-module-jwt 模块下的 /filter 包下,创建 TokenAuthenticationFilter 过滤器,用于专门校验 Token 令牌,代码如下:
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenHelper jwtTokenHelper;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 从请求头中获取 key 为 Authorization 的值
String header = request.getHeader("Authorization");
// 判断 value 值是否以 Bearer 开头
if (StringUtils.startsWith(header, "Bearer")) {
// 截取 Token 令牌
String token = StringUtils.substring(header, 7);
log.info("Token: {}", token);
// 判空 Token
if (StringUtils.isNotBlank(token)) {
try {
// 校验 Token 是否可用, 若解析异常,针对不同异常做出不同的响应参数
jwtTokenHelper.validateToken(token);
} catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e) {
// 抛出异常,统一让 AuthenticationEntryPoint 处理响应参数
authenticationEntryPoint.commence(request, response, new AuthenticationServiceException("Token 不可用"));
return;
} catch (ExpiredJwtException e) {
authenticationEntryPoint.commence(request, response, new AuthenticationServiceException("Token 已失效"));
return;
}
// 从 Token 中解析出用户名
String username = jwtTokenHelper.getUsernameByToken(token);
if (StringUtils.isNotBlank(username)
&& Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
// 根据用户名获取用户详情信息
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 将用户信息存入 authentication,方便后续校验
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, //用户详细信息,凭证,用户权限列表
userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 将 authentication 存入 ThreadLocal,方便后续获取用户信息
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
// 继续执行写一个过滤器
filterChain.doFilter(request, response);
}
}
上述代码中,我们自定义了一个 Spring Security 过滤器 TokenAuthenticationFilter,它继承了 OncePerRequestFilter,确保每个请求只被过滤一次。在重写的 doFilterInternal() 方法中来定义过滤器处理逻辑,首先,从请求头中获取 key 为 Authorization 的值,判断是否以 Bearer 开头,若是,截取出 Token, 对其进行解析,并对可能抛出的异常做出不同的返参。最后,我们获取了用户详情信息,将用户信息存入 authentication,方便后续进行校验,同时将 authentication 存入 ThreadLocal 中,方便后面方便的获取用户信息。
2. JwtTokenHelper 新增方法
上述过滤器中,需要在 JwtTokenHelper 工具类中添加两个方法:
校验 Token 是否可用;
解析 Token 获取用户名;
/**
* 校验 Token 是否可用
* @param token
* @return
*/
public void validateToken(String token) {
jwtParser.parseClaimsJws(token);
}
/**
* 解析 Token 获取用户名
* @param token
* @return
*/
public String getUsernameByToken(String token) {
try {
Claims claims = jwtParser.parseClaimsJws(token).getBody();
String username = claims.getSubject();
return username;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3. 添加处理器
在 /handler 包下,新增 RestAuthenticationEntryPoint 处理器,它专门用来处理当用户未登录时,访问受保护的资源的情况:
/**
* @author: 犬小哈
* @url: www.quanxiaoha.com
* @date: 2023-08-27 17:27
* @description: 用户未登录访问受保护的资源
**/
@Slf4j
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.warn("用户未登录访问受保护的资源: ", authException);
if (authException instanceof InsufficientAuthenticationException) {
ResultUtil.fail(response, HttpStatus.UNAUTHORIZED.value(), Response.fail(ResponseCodeEnum.UNAUTHORIZED));
return;
}
ResultUtil.fail(response, HttpStatus.UNAUTHORIZED.value(), Response.fail(authException.getMessage()));
}
}
当请求相关受保护的接口时,请求头中未携带 Token 令牌,通过日志打印异常信息,你会发现对应的异常类型
对应的,你需要在 ResponseCodeEnum 枚举类中添加 UNAUTHORIZED 枚举值,代码如下:
UNAUTHORIZED("20002", "无访问权限,请先登录!"),
4. RestAccessDeniedHandler
然后,在 /handler 包下,另外新增 RestAccessDeniedHandler 处理器,它主要用于处理当用户登录成功时,访问受保护的资源,但是权限不够的情况:
/**
* @author: 犬小哈
* @url: www.quanxiaoha.com
* @date: 2023-08-27 17:32
* @description: 登录成功访问收保护的资源,但是权限不够
**/
@Slf4j
@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.warn("登录成功访问收保护的资源,但是权限不够: ", accessDeniedException);
// 预留,后面引入多角色时会用到
}
}
5. 修改 Spring Security 配置
完成以上 Token 校验过滤器相关的开发后,接下来,需要将它们添加到 Spring Security 中,编辑 WebSecurityConfig 配置类,修改内容如下:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationSecurityConfig jwtAuthenticationSecurityConfig;
@Autowired
private RestAuthenticationEntryPoint authEntryPoint;
@Autowired
private RestAccessDeniedHandler deniedHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(). // 禁用 csrf
formLogin().disable() // 禁用表单登录
.apply(jwtAuthenticationSecurityConfig) // 设置用户登录认证相关配置
.and()
.authorizeHttpRequests()
.mvcMatchers("/admin/**").authenticated() // 认证所有以 /admin 为前缀的 URL 资源
.anyRequest().permitAll() // 其他都需要放行,无需认证
.and()
.httpBasic().authenticationEntryPoint(authEntryPoint) // 处理用户未登录访问受保护的资源的情况
.and()
.exceptionHandling().accessDeniedHandler(deniedHandler) // 处理登录成功后访问受保护的资源,但是权限不够的情况
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 前后端分离,无需创建会话
.and()
.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 将 Token 校验过滤器添加到用户认证过滤器之前
;
}
/**
* Token 校验过滤器
* @return
*/
@Bean
public TokenAuthenticationFilter tokenAuthenticationFilter() {
return new TokenAuthenticationFilter();
}
}
上述代码中,我们注入了前面写好的相关类,如过滤器、处理器等,主要改动代码如下:
.httpBasic().authenticationEntryPoint(authEntryPoint): 处理用户未登录访问受保护的资源的情况;.exceptionHandling().accessDeniedHandler(deniedHandler): 处理登录成功后访问受保护的资源,但是权限不够的情况;.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class): 将 Token 校验过滤器添加到用户认证过滤器之前;
6. 相关变量提取到 application.yml 中
鉴权功能正常开发完毕后,你会发现已经开发好的代码中,还有一些写死的变量,如请求头的 key, 令牌的失效时间等,其实都是可以提取到 applicaiton.yml 配置文件中,方便后续统一维护的:
jwt:
# token 过期时间(单位:分钟) 24*60
tokenExpireTime: 1440
# token 请求头中的 key 值
tokenHeaderKey: Authorization
# token 请求头中的 value 值前缀
tokenPrefix: Bearer
SpringSecurity配置 2的更多相关文章
- SpringSecurity02 表单登录、SpringSecurity配置类
1 功能需求 springSecuriy默认的登录窗口是一个弹出窗口,而且会默认对所有的请求都进行拦截:要求更改登录页面(使用表单登录).排除掉一些请求的拦截 2 编写一个springSecurity ...
- SpringSecurity配置,简单梳理
生活加油:摘一句子: “我希望自己能写这样的诗.我希望自己也是一颗星星.如果我会发光,就不必害怕黑暗.如果我自己是那么美好,那么一切恐惧就可以烟消云散.于是我开始存下了一点希望—如果我能做到,那么我就 ...
- spring security4.2.2的maven配置+spring-security配置详解+java源码+数据库设计
最近项目需要添加权限拦截,经讨论决定采用spring security4.2.2!废话少说直接上干货! 若有不正之处,请谅解和批评指正,不胜感激!!!!! spring security 4.2.2文 ...
- spring-security 配置简介
1.Spring Security 简介 Spring Security 是一个能够基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在 Spring 应用 ...
- springsecurity 配置swagger
最近在学习springsecurity 安全框架,具体是什么概念在这里不一一赘述了.下面呢,咱们一起搭建一下简单的springsecurity swagger 项目感受一下. 首先初始化spring ...
- spring-security配置和原理简介
SpringSecurity3的核心类有三种 1.URL过滤器或方法拦截器:用来拦截URL或者方法资源对其进行验证,其抽象基类为AbstractSecurityInterceptor 2.资源权限获取 ...
- SpringSecurity 配置
SpringSecurity+JWT https://www.jianshu.com/p/5b9f1f4de88d https://blog.csdn.net/qq_35494808/article/ ...
- Spring-security配置代码
@Configuration public static class WebSecurityConfigurer extends WebSecurityConfigurerAdapter{ @Over ...
- SpringSecurity项目中如何在多个模块中配置认证信息
⒈在SpringSecurity项目中创建AuthorizeConfigProvider接口用于配置认证信息 package cn.coreqi.ssoserver.authorize; import ...
- Spring Boot 5 SpringSecurity身份验证
对于没有访问权限的用户需要转到登录表单页面.要实现访问控制的方法多种多样,可以通过Aop.拦截器实现,也可以通过框架实现(如:Apache Shiro.Spring Security). pom.xm ...
随机推荐
- deepseek: php测试代码执行用时
在 PHP 中,你可以使用 microtime() 函数来测量代码的执行时间.microtime() 函数返回当前 Unix 时间戳的微秒数.你可以在代码的开始和结束处分别调用 microtime() ...
- php 获取post方法payload(json)形式参数的方法
用默认get方式传递的时候,接收方式没有改变,仍然是$_GET. 但是用post方式传递数据的时候,用$_POST无法接收数据,应为小程序默认post发送的content-type为applicati ...
- EAR_v3 《浮声三》 智能化图书管理系统
EAR_v3 <浮声三> 搭建于 Actix_Web 框架下的智能化图书管理系统 本项目的前身是 <Rusty_Borders 危墙> 的 在线控制系统 部分,经过大量开发工作 ...
- abaqus&FEA资料-科研&工具-导航
复合材料力学 BLOGs上的书籍共享文件夹 2004-Mechanics of Composite Structural Elements.pdf,onedrive link Mechanics Of ...
- bp安装+匹配规则(防止抓火狐的多余包)
bp安装使用 BurpLoaderKeygen.jar: 2c8c7b95640f31985f83580402f26a06b78c55877fa33ef1f9d14d2ebb2d8ecd burpsu ...
- LayerSkip: 使用自推测解码加速大模型推理
自推测解码是一种新颖的文本生成方法,它结合了推测解码 (Speculative Decoding) 的优势和大语言模型 (LLM) 的提前退出 (Early Exit) 机制.该方法出自论文 Laye ...
- SpringSecurity学习笔记-前后端分离
1. 简介 Spring Security是Spring家族中的一个安全管理框架.相比于另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富. 一般来说中大型的项目都是使用Sp ...
- 注册全局图标ts写法
https://element-plus.gitee.io/zh-CN/component/icon.html#使用图标 仓库地址:https://github.com/Megasu/element- ...
- oracle修改用户密码的方法
Oracle用户名及默认密码 修改oracle用户的密码有以下方法: 普通用户 (1)通过alter user语法来进行修改 ,这也是最常见的方式: (2) 第二种方式,是通过password命令来修 ...
- OpenAI的GPT-4o:普通人的AI秘书来了
1. 惊艳时刻:AI比你想象的更"人性" 早餐时,张三正埋头刷推送,一篇关于OpenAI发布GPT-4o的文章瞬间点燃了他的好奇心.这个AI简直是科技圈的惊雷!竟然可以像真人一样说 ...