0


Spring Boot 整合SpringSecurity和JWT和Redis实现统一鉴权认证

📑前言

本文主要讲了Spring Security文章,如果有什么需要改进的地方还请大佬指出⛺️

🎬作者简介:大家好,我是青衿🥇
☁️博客首页:CSDN主页放风讲故事
🌄每日一句:努力一点,优秀一点

在这里插入图片描述

目录

文章目录


Spring Security

一、介绍

Spring Security是一个强大且高度可定制的身份验证和访问控制框架。它是保护基于Spring的应用程序的实际标准。Spring Security是一个可以为Java应用程序提供全面安全服务的框架。同时,它也可以轻松扩展以满足自定义需求。

二、主要功能

Authentication (认证),就是用户登录
Authorization (授权):一旦身份验证成功,判断用户拥有什么权限,可以访问什么资源
防止跨站请求伪造(CSRF):Spring Security提供了内置的防护机制,可以防止跨站请求伪造攻击。
密码存储:Spring Security提供了多种密码存储格式,包括明文、加密和哈希。
集成其他安全框架:Spring Security可以与其他安全框架如OAuth2、JWT等进行集成,以提供更全面的安全解决方案。

三、原理

​ SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。

1. SpringSecurity 过滤器链

在这里插入图片描述

SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链。

  • SecurityContextPersistenceFilter:每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中。
  • LogoutFilter:用于处理退出登录。
  • UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。
  • BasicAuthenticationFilter:检测和处理 http basic 认证。
  • ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException 。
  • FilterSecurityInterceptor:负责权限校验的过滤器,可以看做过滤器链的出口。

流程说明:客户端发起一个请求,进入 Security 过滤器链。
1.当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出路径则直接进入下一个过滤器。

2.当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler 登录成功处理器处理,如果不是登录请求则不进入该过滤器。

3.当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器处理。

2. JWT校验登录的校验流程

在这里插入图片描述

首先前端一样是把登录信息发送给后端,后端查询数据库校验用户的账号和密码是否正确,正确的话则使用jwt生成token,并且返回给前端。以后前端每次请求时,都需要携带token,后端获取token后,使用jwt进行验证用户的token是否无效或过期,验证成功后才去做相应的逻辑。

四、Spring Boot整合Redis、SpringSecurity、JWT的示例demo

  1. 添加依赖项在 pom.xml 文件中添加以下依赖项:
   <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>`
  1. 创建Redis配置类
@ConfigurationpublicclassRedisConfig{@Value("${spring.redis.host}")privateString host;@Value("${spring.redis.port}")privateint port;@BeanpublicJedisConnectionFactoryjedisConnectionFactory(){returnnewJedisConnectionFactory(newRedisStandaloneConfiguration(host, port));}@BeanpublicRedisTemplate<String,Object>redisTemplate(){finalRedisTemplate<String,Object> template =newRedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());return template;}}
  1. 创建 JwtTokenUtil 类,用于生成和验证JWT令牌。
@ComponentpublicclassJwtTokenUtilimplementsSerializable{privatestaticfinallong serialVersionUID =-2550185165626007488L;privatestaticfinalString secret ="mySecret";publicStringgetUsernameFromToken(String token){returngetClaimFromToken(token,Claims::getSubject);}publicDategetExpirationDateFromToken(String token){returngetClaimFromToken(token,Claims::getExpiration);}public<T>TgetClaimFromToken(String token,Function<Claims,T> claimsResolver){finalClaims claims =getAllClaimsFromToken(token);return claimsResolver.apply(claims);}privateClaimsgetAllClaimsFromToken(String token){returnJwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}privateBooleanisTokenExpired(String token){finalDate expiration =getExpirationDateFromToken(token);return expiration.before(newDate());}publicStringgenerateToken(UserDetails userDetails){Map<String,Object> claims =newHashMap<>();returndoGenerateToken(claims, userDetails.getUsername());}privateStringdoGenerateToken(Map<String,Object> claims,String subject){returnJwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(newDate(System.currentTimeMillis())).setExpiration(newDate(System.currentTimeMillis()+5*60*60*1000)).signWith(SignatureAlgorithm.HS512, secret).compact();}publicBooleanvalidateToken(String token,UserDetails userDetails){finalString username =getUsernameFromToken(token);return(username.equals(userDetails.getUsername())&&!isTokenExpired(token));}}` 
  1. 创建 JwtAuthenticationEntryPoint 类,用于处理未经授权的请求。
@ComponentpublicclassJwtAuthenticationEntryPointimplementsAuthenticationEntryPoint,Serializable{privatestaticfinallong serialVersionUID =-7858869558953243875L;@Overridepublicvoidcommence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException)throwsIOException{

        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Unauthorized");}}` 
  1. 创建 JwtRequestFilter 类,用于解析和验证JWT令牌。
@ComponentpublicclassJwtRequestFilterextendsOncePerRequestFilter{@AutowiredprivateMyUserDetailsService myUserDetailsService;@AutowiredprivateJwtTokenUtil jwtTokenUtil;@OverrideprotectedvoiddoFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain)throwsServletException,IOException{finalString requestTokenHeader = request.getHeader("Authorization");String username =null;String jwtToken =null;if(requestTokenHeader !=null&& requestTokenHeader.startsWith("Bearer ")){
            jwtToken = requestTokenHeader.substring(7);try{
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);}catch(IllegalArgumentException e){System.out.println("Unable to get JWT Token");}catch(ExpiredJwtException e){System.out.println("JWT Token has expired");}}else{
            logger.warn("JWT Token does not begin with Bearer String");}if(username !=null&&SecurityContextHolder.getContext().getAuthentication()==null){UserDetails userDetails =this.myUserDetailsService.loadUserByUsername(username);if(jwtTokenUtil.validateToken(jwtToken, userDetails)){UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =newUsernamePasswordAuthenticationToken(
                        userDetails,null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(newWebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);}}
        chain.doFilter(request, response);}}` 
  1. 配置Spring Security
@Configuration@EnableWebSecuritypublicclassWebSecurityConfigextendsWebSecurityConfigurerAdapter{@AutowiredprivateJwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;@AutowiredprivateUserDetailsService jwtUserDetailsService;@AutowiredprivateJwtRequestFilter jwtRequestFilter;@AutowiredpublicvoidconfigureGlobal(AuthenticationManagerBuilder auth)throwsException{
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());}@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}@Bean@OverridepublicAuthenticationManagerauthenticationManagerBean()throwsException{returnsuper.authenticationManagerBean();}@Overrideprotectedvoidconfigure(HttpSecurity httpSecurity)throwsException{
        httpSecurity.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll().anyRequest().authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter,UsernamePasswordAuthenticationFilter.class);}}`

以上是简单的Spring Boot整合Redis、Security、JWT和Redis的示例,可以根据自己的实际需求进行调整。

📑文章末尾

在这里插入图片描述


本文转载自: https://blog.csdn.net/2301_80092713/article/details/134215105
版权归原作者 放风讲故事 所有, 如有侵权,请联系我们删除。

“Spring Boot 整合SpringSecurity和JWT和Redis实现统一鉴权认证”的评论:

还没有评论