SpringBoot整合SpringSecurity和JWT和Redis實(shí)現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證
一、介紹
Spring Security是一個(gè)強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架。它是保護(hù)基于Spring的應(yīng)用程序的實(shí)際標(biāo)準(zhǔn)。Spring Security是一個(gè)可以為Java應(yīng)用程序提供全面安全服務(wù)的框架。同時(shí),它也可以輕松擴(kuò)展以滿足自定義需求。
二、主要功能
Authentication (認(rèn)證),就是用戶登錄
Authorization (授權(quán)):一旦身份驗(yàn)證成功,判斷用戶擁有什么權(quán)限,可以訪問什么資源
防止跨站請(qǐng)求偽造(CSRF):Spring Security提供了內(nèi)置的防護(hù)機(jī)制,可以防止跨站請(qǐng)求偽造攻擊。
密碼存儲(chǔ):Spring Security提供了多種密碼存儲(chǔ)格式,包括明文、加密和哈希。
集成其他安全框架:Spring Security可以與其他安全框架如OAuth2、JWT等進(jìn)行集成,以提供更全面的安全解決方案。
三、原理
? SpringSecurity的原理其實(shí)就是一個(gè)過濾器鏈,內(nèi)部包含了提供各種功能的過濾器。
1. SpringSecurity 過濾器鏈
SpringSecurity 采用的是責(zé)任鏈的設(shè)計(jì)模式,它有一條很長(zhǎng)的過濾器鏈。
- SecurityContextPersistenceFilter:每次請(qǐng)求處理之前將該請(qǐng)求相關(guān)的安全上下文信息加載到 SecurityContextHolder 中。
- LogoutFilter:用于處理退出登錄。
- UsernamePasswordAuthenticationFilter:用于處理基于表單的登錄請(qǐng)求,從表單中獲取用戶名和密碼。
- BasicAuthenticationFilter:檢測(cè)和處理 http basic 認(rèn)證。
- ExceptionTranslationFilter:處理過濾器鏈中拋出的任何AccessDeniedException和AuthenticationException 。
- FilterSecurityInterceptor:負(fù)責(zé)權(quán)限校驗(yàn)的過濾器,可以看做過濾器鏈的出口。
- …
流程說明:客戶端發(fā)起一個(gè)請(qǐng)求,進(jìn)入 Security 過濾器鏈。
1.當(dāng)?shù)?LogoutFilter 的時(shí)候判斷是否是登出路徑,如果是登出路徑則到 logoutHandler ,如果登出成功則到logoutSuccessHandler 登出成功處理,如果登出失敗則由 ExceptionTranslationFilter ;如果不是登出路徑則直接進(jìn)入下一個(gè)過濾器。
2.當(dāng)?shù)?UsernamePasswordAuthenticationFilter 的時(shí)候判斷是否為登錄路徑,如果是,則進(jìn)入該過濾器進(jìn)行登錄操作,如果登錄失敗則到 AuthenticationFailureHandler 登錄失敗處理器處理,如果登錄成功則到 AuthenticationSuccessHandler 登錄成功處理器處理,如果不是登錄請(qǐng)求則不進(jìn)入該過濾器。
3.當(dāng)?shù)?FilterSecurityInterceptor 的時(shí)候會(huì)拿到 uri ,根據(jù) uri 去找對(duì)應(yīng)的鑒權(quán)管理器,鑒權(quán)管理器做鑒權(quán)工作,鑒權(quán)成功則到 Controller 層否則到 AccessDeniedHandler 鑒權(quán)失敗處理器處理。
2. JWT校驗(yàn)登錄的校驗(yàn)流程
首先前端一樣是把登錄信息發(fā)送給后端,后端查詢數(shù)據(jù)庫校驗(yàn)用戶的賬號(hào)和密碼是否正確,正確的話則使用jwt生成token,并且返回給前端。以后前端每次請(qǐng)求時(shí),都需要攜帶token,后端獲取token后,使用jwt進(jìn)行驗(yàn)證用戶的token是否無效或過期,驗(yàn)證成功后才去做相應(yīng)的邏輯。
四、Spring Boot整合Redis、SpringSecurity、JWT的示例demo
- 添加依賴項(xiàng)在
pom.xml
文件中添加以下依賴項(xiàng):
<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>`
- 創(chuàng)建Redis配置類
@Configuration public class RedisConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Bean public JedisConnectionFactory jedisConnectionFactory() { return new JedisConnectionFactory(new RedisStandaloneConfiguration(host, port)); } @Bean public RedisTemplate<String, Object> redisTemplate() { final RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(jedisConnectionFactory()); return template; } }
- 創(chuàng)建
JwtTokenUtil
類,用于生成和驗(yàn)證JWT令牌。
@Component public class JwtTokenUtil implements Serializable { private static final long serialVersionUID = -2550185165626007488L; private static final String secret = "mySecret"; public String getUsernameFromToken(String token) { return getClaimFromToken(token, Claims::getSubject); } public Date getExpirationDateFromToken(String token) { return getClaimFromToken(token, Claims::getExpiration); } public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } private Claims getAllClaimsFromToken(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); return doGenerateToken(claims, userDetails.getUsername()); } private String doGenerateToken(Map<String, Object> claims, String subject) { return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 5 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS512, secret).compact(); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } }`
- 創(chuàng)建
JwtAuthenticationEntryPoint
類,用于處理未經(jīng)授權(quán)的請(qǐng)求。
@Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -7858869558953243875L; @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); } }`
- 創(chuàng)建
JwtRequestFilter
類,用于解析和驗(yàn)證JWT令牌。
@Component public class JwtRequestFilter extends OncePerRequestFilter { @Autowired private MyUserDetailsService myUserDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { final String 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 = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); usernamePasswordAuthenticationToken .setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); } } chain.doFilter(request, response); } }`
- 配置Spring Security
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private UserDetailsService jwtUserDetailsService; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable() .authorizeRequests().antMatchers("/authenticate").permitAll(). anyRequest().authenticated().and(). exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } }`
以上是簡(jiǎn)單的Spring Boot整合Redis、Security、JWT和Redis的示例,可以根據(jù)自己的實(shí)際需求進(jìn)行調(diào)整。更多相關(guān)SpringBoot 統(tǒng)一鑒權(quán)認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringSecurity6.0 如何通過JWTtoken進(jìn)行認(rèn)證授權(quán)
- springSecurity自定義登錄接口和JWT認(rèn)證過濾器的流程
- SpringSecurity+jwt+captcha登錄認(rèn)證授權(quán)流程總結(jié)
- SpringSecurity+Redis+Jwt實(shí)現(xiàn)用戶認(rèn)證授權(quán)
- SpringSecurity+jwt+redis基于數(shù)據(jù)庫登錄認(rèn)證的實(shí)現(xiàn)
- SpringBoot+SpringSecurity+JWT實(shí)現(xiàn)系統(tǒng)認(rèn)證與授權(quán)示例
- SpringBoot整合SpringSecurity實(shí)現(xiàn)JWT認(rèn)證的項(xiàng)目實(shí)踐
- SpringSecurity整合jwt權(quán)限認(rèn)證的全流程講解
- SpringSecurity構(gòu)建基于JWT的登錄認(rèn)證實(shí)現(xiàn)
- SpringSecurity JWT基于令牌的無狀態(tài)認(rèn)證實(shí)現(xiàn)
相關(guān)文章
Shiro實(shí)現(xiàn)session限制登錄數(shù)量踢人下線功能
這篇文章主要介紹了Shiro實(shí)現(xiàn)session限制登錄數(shù)量踢人下線,本文記錄的是shiro采用session作為登錄方案時(shí),對(duì)用戶進(jìn)行限制數(shù)量登錄,以及剔除下線,需要的朋友可以參考下2023-11-11Springboot定時(shí)任務(wù)Scheduled重復(fù)執(zhí)行操作
這篇文章主要介紹了Springboot定時(shí)任務(wù)Scheduled重復(fù)執(zhí)行操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09使用filter實(shí)現(xiàn)url級(jí)別內(nèi)存緩存示例
這篇文章主要介紹了使用filter實(shí)現(xiàn)url級(jí)別內(nèi)存緩存示例,只需要一個(gè)靜態(tài)類,在filter中調(diào)用,也可以全部寫到filt里面??梢愿鶕?jù)查詢參數(shù)分別緩存,需要的朋友可以參考下2014-03-03AJAX省市區(qū)三級(jí)聯(lián)動(dòng)下拉菜單(java版)
這篇文章主要介紹了AJAX省市區(qū)三級(jí)聯(lián)動(dòng)下拉菜單(java版)的相關(guān)資料,需要的朋友可以參考下2016-01-01