??前言
本文主要講了Spring Security文章,如果有什么需要改進(jìn)的地方還請(qǐng)大佬指出??
??作者簡(jiǎn)介:大家好,我是青衿??
??博客首頁(yè):CSDN主頁(yè)放風(fēng)講故事
??每日一句:努力一點(diǎn),優(yōu)秀一點(diǎn)
目錄
Spring Security
一、介紹
Spring Security是一個(gè)強(qiáng)大且高度可定制的身份驗(yàn)證和訪問(wè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)限,可以訪問(wè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è)過(guò)濾器鏈,內(nèi)部包含了提供各種功能的過(guò)濾器。
1. SpringSecurity 過(guò)濾器鏈
SpringSecurity 采用的是責(zé)任鏈的設(shè)計(jì)模式,它有一條很長(zhǎng)的過(guò)濾器鏈。
- SecurityContextPersistenceFilter:每次請(qǐng)求處理之前將該請(qǐng)求相關(guān)的安全上下文信息加載到 SecurityContextHolder 中。
- LogoutFilter:用于處理退出登錄。
- UsernamePasswordAuthenticationFilter:用于處理基于表單的登錄請(qǐng)求,從表單中獲取用戶名和密碼。
- BasicAuthenticationFilter:檢測(cè)和處理 http basic 認(rèn)證。
- ExceptionTranslationFilter:處理過(guò)濾器鏈中拋出的任何AccessDeniedException和AuthenticationException 。
- FilterSecurityInterceptor:負(fù)責(zé)權(quán)限校驗(yàn)的過(guò)濾器,可以看做過(guò)濾器鏈的出口。
- …
流程說(shuō)明:客戶端發(fā)起一個(gè)請(qǐng)求,進(jìn)入 Security 過(guò)濾器鏈。
1.當(dāng)?shù)?LogoutFilter 的時(shí)候判斷是否是登出路徑,如果是登出路徑則到 logoutHandler ,如果登出成功則到logoutSuccessHandler 登出成功處理,如果登出失敗則由 ExceptionTranslationFilter ;如果不是登出路徑則直接進(jìn)入下一個(gè)過(guò)濾器。
2.當(dāng)?shù)?UsernamePasswordAuthenticationFilter 的時(shí)候判斷是否為登錄路徑,如果是,則進(jìn)入該過(guò)濾器進(jìn)行登錄操作,如果登錄失敗則到 AuthenticationFailureHandler 登錄失敗處理器處理,如果登錄成功則到 AuthenticationSuccessHandler 登錄成功處理器處理,如果不是登錄請(qǐng)求則不進(jìn)入該過(guò)濾器。
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ù)庫(kù)校驗(yàn)用戶的賬號(hào)和密碼是否正確,正確的話則使用jwt生成token,并且返回給前端。以后前端每次請(qǐng)求時(shí),都需要攜帶token,后端獲取token后,使用jwt進(jìn)行驗(yàn)證用戶的token是否無(wú)效或過(guò)期,驗(yàn)證成功后才去做相應(yīng)的邏輯。
四、Spring Boot整合Redis、SpringSecurity、JWT的示例demo
- 添加依賴(lài)項(xiàng)在
pom.xml
文件中添加以下依賴(lài)項(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配置類(lèi)
@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
類(lèi),用于生成和驗(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
類(lèi),用于處理未經(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
類(lèi),用于解析和驗(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)整。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-744802.html
??文章末尾
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-744802.html
到了這里,關(guān)于Spring Boot 整合SpringSecurity和JWT和Redis實(shí)現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!