本人使用版本为 springboot 2.7.1 ,jdk17
项目结构文件如图所示:

每个文件的介绍

  • 1,pom.xml的依赖:
  • 2,CorsFilter:由于项目采用前后端分离,则涉及到跨域问题,所以进行跨域配置。
  • 3,JWTFilter:获取请求头中jwt,然后解析出认证和授权信息,存入SecurityContextHolder
  • 4,AuthenticationAdapter:处理登录成功(生成jwt)与失败
  • 5,MyAccessDeniedHandler:认证成功后但权限不足时异常处理
  • 6,MyAuthenticationEntryPoint:未认证时,提供认证入口(提示未认证)
  • 6,MyAuthenticationManager:认证管理器,这里没有去管理,而是直接去认证
  • 7,MyUserDetailsService:根据用户名查找用户,模拟查找数据库,授权
  • 8,WebSecurityConfig:security 核心配置
  • 9,剩下几个工具类

1,pom.xml的依赖:

     <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.0.0</version></dependency>

2,CorsFilter:由于项目采用前后端分离,则涉及到跨域问题,所以进行跨域配置。

public class CorsFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {response.addHeader("Access-Control-Expose-Headers", "Authorization");response.addHeader("Access-Control-Allow-Headers", "Content-Type,FILENAME,CATEGORY,FILESIZE,Authorization");String origin = request.getHeader("origin");response.addHeader("Access-Control-Allow-Origin", origin == null ? "*" : origin);response.addHeader("Access-Control-Request-Headers", "Authorization");filterChain.doFilter(request, response);}
}

3,JWTFilter:获取请求头中jwt,然后解析出认证和授权信息,存入SecurityContextHolder

public class JWTFilter extends OncePerRequestFilter {//    此过略器加在UsernamePasswordAuthenticationFilter之后
//    进入该过滤器则,不是登录请求,若请求中含有jwt,则解码后存入SecurityContextHolder
//    最后清除SecurityContextHolder@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String header = request.getHeader(TokenUtils.AUTHORIZATION);String token = TokenUtils.getToken(header);if (token != null) {JwtTool.UserWrapper wrapper = JwtTool.decode(token);if (wrapper != null) {SecurityContext context = SecurityContextHolder.createEmptyContext();List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(wrapper.authorities);context.setAuthentication(new UsernamePasswordAuthenticationToken(new User(wrapper.username, Strings.EMPTY, authorities),Strings.EMPTY,authorities));SecurityContextHolder.setContext(context);if (wrapper.shouldRefresh) {String jwt = JwtTool.createJWT(wrapper);response.addHeader(TokenUtils.AUTHORIZATION, TokenUtils.getAuthorizationValue(jwt));}}}filterChain.doFilter(request, response);SecurityContextHolder.clearContext();}
}

4,AuthenticationAdapter:处理登录成功(生成jwt)与失败

@Configuration
public class AuthenticationHandleAdapter implements AuthenticationSuccessHandler, AuthenticationFailureHandler {private final ObjectMapper objectMapper;public AuthenticationHandleAdapter(ObjectMapper objectMapper) {this.objectMapper = objectMapper;}@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException {//        生成JWT,返回给前端if (authentication.getPrincipal() instanceof User user) {Collection<GrantedAuthority> authorities = user.getAuthorities();String[] authoritiesStr = authorities.stream().map(GrantedAuthority::getAuthority).toList().toArray(new String[authorities.size()]);String jwt = JwtTool.createJWT(new JwtTool.UserWrapper(user.getUsername(), null, authoritiesStr));response.addHeader(TokenUtils.AUTHORIZATION, TokenUtils.getAuthorizationValue(jwt));}ResponseUtils.write(response, objectMapper.writeValueAsString(new Result("authentication successful")));}@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException {ResponseUtils.write(response, objectMapper.writeValueAsString(new Result(400,"authentication failed",exception.getMessage())));}}

5,MyAccessDeniedHandler:认证成功后但权限不足时异常处理

@Configuration
public class MyAccessDeniedHandler implements AccessDeniedHandler {private final ObjectMapper objectMapper;public MyAccessDeniedHandler(ObjectMapper objectMapper) {this.objectMapper = objectMapper;}@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException accessDeniedException) throws IOException {ResponseUtils.write(response, objectMapper.writeValueAsString(new Result(403,accessDeniedException.getMessage())));}
}

6,MyAuthenticationEntryPoint:未认证时,提供认证入口(提示未认证)

@Configuration
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {private final ObjectMapper objectMapper;public MyAuthenticationEntryPoint(ObjectMapper objectMapper) {this.objectMapper = objectMapper;}@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {ResponseUtils.write(response, objectMapper.writeValueAsString(new Result(403, authException.getMessage())));}
}

6,MyAuthenticationManager:认证管理器,这里没有去管理,而是直接去认证

@Configuration
public class MyAuthenticationManager implements AuthenticationManager {private final UserDetailsService userDetailsService;private final PasswordEncoder passwordEncoder;public MyAuthenticationManager(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {this.userDetailsService = userDetailsService;this.passwordEncoder = passwordEncoder;}@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());if (!passwordEncoder.matches((String) authentication.getCredentials(), userDetails.getPassword())) {throw new BadCredentialsException("用户名或密码错误");}return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials(),userDetails.getAuthorities());}
}

7,MyUserDetailsService:根据用户名查找用户,模拟查找数据库,授权

@Configuration
public class MyUserDetailsService implements UserDetailsService {private final Map<String, String> users = Map.of("user1", "authority1", "user2", "authority2");@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//      省略在数据库查找用户,此时通用密码为123456String password = new BCryptPasswordEncoder().encode("123456");if (!users.containsKey(username)) {throw new UsernameNotFoundException("没有找到用户名!!");}List<GrantedAuthority> grantedAuthorities = AuthorityUtils.createAuthorityList(users.get(username));return new User(username, password, grantedAuthorities);}
}

8,WebSecurityConfig:security 核心配置

@Configuration
public class WebSecurityConfig {@BeanPasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}@BeanSecurityFilterChain filterChain(HttpSecurity http,MyAuthenticationManager authenticationManager,MyAccessDeniedHandler accessDeniedHandler,MyAuthenticationEntryPoint authenticationEntryPoint,AuthenticationHandleAdapter authenticationHandler) throws Exception {return http.authorizeRequests(authorizeRequests -> authorizeRequests.antMatchers("/hello").authenticated().antMatchers("/authority1").hasAuthority("authority1").antMatchers("/authority2").hasAuthority("authority2")).formLogin(customizer -> customizer.successHandler(authenticationHandler).failureHandler(authenticationHandler).loginProcessingUrl("/login")).exceptionHandling(exceptionHandling -> exceptionHandling.accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(authenticationEntryPoint)).addFilterBefore(new CorsFilter(), UsernamePasswordAuthenticationFilter.class).addFilterAfter(new JWTFilter(), UsernamePasswordAuthenticationFilter.class).authenticationManager(authenticationManager).sessionManagement().disable().securityContext().disable().requestCache().disable().rememberMe().disable().logout().disable().csrf().disable().build();}
}

9,剩下几个工具类

public class JwtTool {private static final Logger logger = LoggerFactory.getLogger(JwtTool.class);//    120分钟//    超时则过期private static final long period = 1000 * 60 * 120;//    超过有效时间的0.4则刷新tokenprivate static final double tokenRefreshPeriod = period * 0.4;private static final Algorithm signature = Algorithm.HMAC256("23443");private static final JWTVerifier verifier = JWT.require(signature).build();public static String createJWT(UserWrapper wrapper) {return JWT.create().withExpiresAt(new Date(System.currentTimeMillis() + period)).withClaim("username", wrapper.username).withClaim("userId", wrapper.userId).withArrayClaim("authorities", wrapper.authorities).sign(signature);}public static UserWrapper decode(String token) {DecodedJWT decodedJWT;try{decodedJWT = verifier.verify(token);}catch (JWTVerificationException e){logger.debug(e.getMessage());return null;}Integer userId = decodedJWT.getClaim("userId").asInt();String username = decodedJWT.getClaim("username").asString();String[] authorities = decodedJWT.getClaim("authorities").asArray(String.class);UserWrapper wrapper = new UserWrapper(username, userId, authorities);wrapper.shouldRefresh =decodedJWT.getExpiresAt().getTime()- System.currentTimeMillis() < period - tokenRefreshPeriod;return wrapper;}public static class UserWrapper {public String username;public Integer userId;public String[] authorities;public boolean shouldRefresh;public UserWrapper(String username, Integer userId, String[] authorities) {this.username = username;this.userId = userId;this.authorities = authorities;}}
}
public class ResponseUtils {public static void  write(HttpServletResponse response, String json){try {response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding("UTF-8");response.getWriter().print(json);response.getWriter().flush();} catch (IOException e) {e.printStackTrace();}}
}
@Data()
public class Result {private Integer code;private String message;private Object data;public Result() {}public Result(Integer code, String message, Object data) {this.code = code;this.message = message;this.data = data;}public Result(Integer code, String message) {this.code = code;this.message = message;}public Result(String message) {this.code = 200;this.message = message;}
}
public class TokenUtils {private static final String bearer = "Bearer ";public static final String AUTHORIZATION = "Authorization";public static String getToken(String authorizationValue) {if (authorizationValue != null && authorizationValue.startsWith(bearer)) {return authorizationValue.substring(bearer.length());}return null;}public static String getAuthorizationValue(String token) {return bearer + token;}
}

Spring Security + JWT简单配置相关推荐

  1. springboot jwt token前后端分离_基于Spring Boot+Spring Security+JWT+Vue前后端分离的开源项目...

    一.前言 最近整合Spring Boot+Spring Security+JWT+Vue 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...

  2. 超实用,Spring Security+JWT+Vue实现一个前后端分离无状态认证Demo

    作者: 陕西颜值扛把子 https://zhuanlan.zhihu.com/p/95560389 精彩推荐 一百期Java面试题汇总 SpringBoot内容聚合 IntelliJ IDEA内容聚合 ...

  3. spring boot +spring security + jwt 实现认证模块

    我在使用spring进行开发时,通常是使用 aop+jwt 模式来对调用者身份进行确认.前几天接触到一个开源商城源码(github地址)里面使用spring security +jwt 来进行权限的验 ...

  4. Springboot Spring Security +Jwt+redis+mybatisPlus 动态完成 前后端分离认证授权

    Springboot Spring Security +Jwt 动态完成 前后端分离认证授权 文章目录 Springboot Spring Security +Jwt 动态完成 前后端分离认证授权 前 ...

  5. Spring Boot+Spring Security+JWT 实现token验证

    Spring Boot+Spring Security+JWT 实现token验证 什么是JWT? JWT的工作流程 JWT的主要应用场景 JWT的结构 SpringBoot+Spring Secur ...

  6. Angular 6集成Spring Boot 2,Spring Security,JWT和CORS

    主要内容:Spring Boot 2的基础应用.CORS配置.Actuator监控:Spring Boot集成springfox-swagger,利用Swagger生成JSON API文档,利用Swa ...

  7. Java开发 - 单点登录初体验(Spring Security + JWT)

    目录​​​​​​​ 前言 为什么要登录 登录的种类 Cookie-Session Cookie-Session-local storage JWT令牌 几种登陆总结 用户身份认证与授权 创建工程 添加 ...

  8. 使用Spring Security进行简单身份验证

    朋友不允许朋友写用户身份验证. 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK. 在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护. 身份验证对于除了最基本的Web应 ...

  9. Spring boot 整合Spring Security Jwt

    记录学习Spring boot 整合Spring Security Jwt 学习参考 – 慢慢的干货 https://shimo.im/docs/OnZDwoxFFL8bnP1c/read 首先创建S ...

最新文章

  1. AI一分钟 | 搜狗王小川:今年重点战略是输入法升级和发展机器翻译;北京无人驾驶试验场下半年正式运营
  2. 电脑字体在哪个文件夹_电脑键盘使用方法
  3. 第2章 熟悉Eclipse开发工具---- System.out.println(sum=+(a+b));
  4. 5 java中的集合类_java基础(5)-集合类1
  5. 利用计算机来模仿人,如何模仿人的学习模式来教计算机程序解数学题?
  6. CentOS7搭建hadoop2.6.4+HBase1.1.6
  7. 『数据库』 E-R图(实体联系图)你都不会,你设计什么数据库?
  8. 【 Date 对象 参考手册】
  9. 【每日SQL打卡】DAY 1丨部门工资最高的员工【难度中等】
  10. .net 数据存储 mysql_asp.net实现存储和读取数据库图片
  11. Mac 下利用 Launchctl 自启动 mysql
  12. 《Java并发编程的艺术》:第2章 Java并发机制的底层实现原理
  13. c语言贪心算法合并箭,贪心算法:用最少数量的箭引爆气球
  14. php与mysql事物处理
  15. 微信公众号如何开通支付功能?
  16. 【CentOS8.0开启防火墙放行8081端口】
  17. sed替换指定字符串为某变量的值
  18. 可以使用python开发财务软件吗_给还准备继续做审计的人提个醒!
  19. 16g电脑内存有什么好处_16G电脑运行内存可以达到什么样子。
  20. js bind 传参、_Node.js 在微医的应用场景及实践

热门文章

  1. 黑客爱用的 HOOK 技术大揭秘!
  2. Twitch联合创始人推出游戏NFT市场Fractal
  3. DC/AC:单相方波全桥逆变电路设计原理及实验仿真
  4. 计算机组装基地,系统基地装机大师工具装机版V6.5
  5. 第十次作业整理(数据可视化与地图/20211126)
  6. [软件设置]安装了McAfee杀毒软件后,用Foxmail发送邮件总是显示“由于目标机器积极拒绝,无法连接”解决方案
  7. 在线工具推荐!能在线解决的问题,何必下载软件呢?
  8. 气象站:处暑至热未止,从事不同行业的人们应该如何预知天气变化
  9. 从穆迪上调评级,看联想集团高质量战略转型
  10. 对话 Do Kwon :流亡、谎言和梦醒时分的懊悔