中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站維護(hù) 收錄湖南長沙最新疫情

網(wǎng)站維護(hù) 收錄,湖南長沙最新疫情,wordpress自然志,wordpress 數(shù)據(jù)表結(jié)構(gòu)一定要熟悉spring security原理和jwt無狀態(tài)原理,理解了才知道代碼作用。 在 Spring Security JWT 認(rèn)證流程中,通常的做法是: 用戶提交用戶名和密碼Spring Security 認(rèn)證管理器 (AuthenticationManager) 進(jìn)行認(rèn)證如果認(rèn)證成功,生…

一定要熟悉spring security原理和jwt無狀態(tài)原理,理解了才知道代碼作用。

Spring Security + JWT 認(rèn)證流程中,通常的做法是:

  1. 用戶提交用戶名和密碼
  2. Spring Security 認(rèn)證管理器 (AuthenticationManager) 進(jìn)行認(rèn)證
  3. 如果認(rèn)證成功,生成 JWT Token 并返回給用戶

更詳細(xì)一點(diǎn)

  1. 用戶首次登錄

    • 發(fā)送 POST /login 請求,攜帶 用戶名 + 密碼
    • authenticationManager.authenticate() 認(rèn)證成功后,返回 JWT
    • 前端存儲 JWT(通常是 localStoragesessionStorage
  2. 用戶訪問受保護(hù)接口

    • 前端在 Authorization 頭中附帶 Bearer Token
    • 過濾器 JWTFilter 解析 JWT,從 數(shù)據(jù)庫 加載 UserDetails
    • SecurityContextHolder.setAuthentication() 認(rèn)證成功,繼續(xù)訪問資源。

參考鏈接有:

spring security 超詳細(xì)使用教程(接入springboot、前后端分離) - 小程xy - 博客園

SpringSecurity+jwt實(shí)現(xiàn)權(quán)限認(rèn)證功能_spring security + jwt-CSDN博客

1.引入相關(guān)依賴。我使用的是springboot3.3.5? ?springsecurity是6.x的? jwt 0.12.6

<dependencies><!--用于數(shù)據(jù)加密,默認(rèn)啟用--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-crypto</artifactId></dependency>
</dependencies><!--依賴集中管理--><dependencyManagement><dependencies><!-- 使用jwt進(jìn)行token驗證,包括了三個依賴--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.12.6</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.12.6</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.12.6</version> <scope>runtime</scope> </dependency><dependencies></dependencyManagement>

2.配置SecurityConfig.java

package com.x.x.x.config;import com.x.x.x.filter.CustomFilter;
import com.x.x.x.filter.JwtAuthenticationTokenFilter;
import com.x.x.x.security.service.impl.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
public class SecurityConfig {/*** 用戶名和密碼也可以在application.properties中設(shè)置。* @return*/@Beanpublic UserDetailsService userDetailsService() {// 創(chuàng)建基于內(nèi)存的用戶信息管理器InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();// 創(chuàng)建UserDetails對象,用于管理用戶名、用戶密碼、用戶角色、用戶權(quán)限等內(nèi)容manager.createUser(User.withUsername("admin").password("yourpassword").roles("ADMIN").build());return manager;}/*** 認(rèn)證管理。     jwt的用戶驗證* @param authConfig* @return* @throws Exception*/@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {return authConfig.getAuthenticationManager();}/*** 認(rèn)證的token過濾器* @return*/@Beanpublic JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){return new JwtAuthenticationTokenFilter();}/*** 密碼加碼* @return*/@Beanpublic PasswordEncoder passwordEncoder() {// 也可用有參構(gòu)造,取值范圍是 4 到 31,默認(rèn)值為 10。數(shù)值越大,加密計算越復(fù)雜return new BCryptPasswordEncoder();}/*** 配置過濾鏈* 配置自動注銷功能必須在函數(shù)里加UserDetailsService userDetailsService,因為重寫了使用數(shù)據(jù)庫認(rèn)證所以用baseuserserviceimpl* @param http* @return* @throws Exception*/@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http,  UserDetailsServiceImpl userDetailsService) throws Exception {http// 開啟授權(quán)保護(hù),配置請求授權(quán)規(guī)則.authorizeHttpRequests(authorize -> authorize.requestMatchers("/login","/mylogin","/druid/**").permitAll()   // 不需要認(rèn)證的地址有哪些  ("/blog/**", "/public/**", "/about").anyRequest()      // 對所有請求開啟授權(quán)保護(hù).authenticated()   // 已認(rèn)證的請求會被自動授權(quán))// 配置自定義登錄頁面// 本處禁用前端頁面,使用功能RESTful風(fēng)格前后端分離,就是不用登錄頁面.formLogin(form -> form.disable()).httpBasic(Customizer -> Customizer.disable())// 啟用記住我功能。允許用戶關(guān)閉瀏覽器后仍然保持登錄狀態(tài),直到主動注銷或者查出設(shè)定過期時間//.rememberMe(Customizer.withDefaults()).rememberMe(rememberMe -> rememberMe.key("uniqueAndSecret") // 設(shè)置一個密鑰.tokenValiditySeconds(2 * 24 * 60 * 60) // 設(shè)置 RememberMe token 的有效期.userDetailsService(userDetailsService) // 顯式設(shè)置 UserDetailsService)// 配置注銷功能.logout(logout -> logout.logoutUrl("/perform_logout") // 自定義注銷請求路徑//.logoutSuccessUrl("/login?logout=true") // 注銷成功后的跳轉(zhuǎn)頁面.deleteCookies("JSESSIONID") // 刪除指定的 Cookie.permitAll() // 允許所有用戶注銷).sessionManagement(session -> session.sessionFixation(SessionManagementConfigurer.SessionFixationConfigurer::changeSessionId)  // 防止會話固定攻擊.maximumSessions(1) // 限制每個用戶只能有一個活躍會話.maxSessionsPreventsLogin(false)// 如果為 true,禁止新登錄;為 false,允許新登錄并終止舊會話.expiredUrl("/login?session=expired") // 當(dāng)會話過期時跳轉(zhuǎn)到的頁面);// 關(guān)閉 csrf CSRF(跨站請求偽造)是一種網(wǎng)絡(luò)攻擊,攻擊者通過欺騙已登錄用戶,誘使他們在不知情的情況下向受信任的網(wǎng)站發(fā)送請求。http.csrf(csrf -> csrf.disable());// 注冊自定義的過濾器CustomFilter// 用于jwt 功能確保過濾器的邏輯在每個請求中只執(zhí)行一次,非常適合需要對每個請求進(jìn)行處理的場景http.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class);//已經(jīng)在customfilter中重寫 http.addFilterBefore(new JwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);//授權(quán)認(rèn)證,基于角色在 Spring Security 6.x 版本中,antMatchers() 方法已被移除,取而代之的是使用新的基于 請求匹配器 (RequestMatchers) 的方法/*http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/admin/**").hasRole("ADMIN")  // 只有 ADMIN 角色可以訪問.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")  // USER 和 ADMIN 角色可以訪問.anyRequest().authenticated());  // 其他請求需要認(rèn)證//基于權(quán)限的授權(quán),編輯權(quán)限還是只讀等http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/edit/**").hasAuthority("EDIT_PRIVILEGE")  // 僅具有 EDIT_PRIVILEGE 權(quán)限的用戶可以訪問.anyRequest().authenticated());  // 其他請求需要認(rèn)證*/return http.build();}
}

3.重寫loadUserByUsername的方法。

(1)UserDetailsImpl.java

package com.x.x.x.security.service.impl;import com.x.x.x.entity.BaseUsers;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;
import java.util.List;@Data
@AllArgsConstructor
@NoArgsConstructor    // 這三個注解可以幫我們自動生成 get、set、有參、無參構(gòu)造函數(shù)
public class UserDetailsImpl implements UserDetails {private BaseUsers baseUsers;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return List.of();}@Overridepublic String getPassword() {return baseUsers.getPassword();}@Overridepublic String getUsername() {return baseUsers.getOaId();}@Overridepublic boolean isAccountNonExpired() {  // 檢查賬戶是否 沒過期。return true;}@Overridepublic boolean isAccountNonLocked() {   // 檢查賬戶是否 沒有被鎖定。return true;}@Overridepublic boolean isCredentialsNonExpired() {  //檢查憑據(jù)(密碼)是否 沒過期。return true;}@Overridepublic boolean isEnabled() {    // 檢查賬戶是否啟用。return true;}// 這個方法是 @Data注解 會自動幫我們生成,用來獲取 loadUserByUsername 中最后我們返回的創(chuàng)建UserDetailsImpl對象時傳入的User。// 如果你的字段包含 username和password 的話可以用強(qiáng)制類型轉(zhuǎn)換, 把 UserDetailsImpl 轉(zhuǎn)換成 User。如果不能強(qiáng)制類型轉(zhuǎn)換的話就需要用到這個方法了public BaseUsers getUser() {return baseUsers;}
}

(2)UserDetailsServiceImpl.java

package com.x.x.x.security.service.impl;import com.x.x.x.entity.BaseUsers;
import com.x.x.x.service.BaseUsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate BaseUsersService baseUsersService;/*** 重寫loadUserByUsername方法* @param username the username identifying the user whose data is required.* @return* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {BaseUsers baseUsers = new BaseUsers();baseUsers.setOaId(username);List<BaseUsers> baseUsersList = baseUsersService.queryUsersList(baseUsers);if (baseUsersList == null || baseUsersList.isEmpty()) {System.out.println("------------->       loadUserByUsername驗證失敗, "+baseUsers.getOaId()+" 不存在!");throw new UsernameNotFoundException(username);}return new UserDetailsImpl(baseUsersList.get(0));	// UserDetailsImpl 是我們實(shí)現(xiàn)的類}
}

4.JwtAuthenticationProvider.java繼承重新AuthenticationProvider的authenticate方法。這里注意可能未使用我們繼承的userDetailsService,所以使用@Qualifier("")指定

package com.x.x.x.security.handler;import io.micrometer.common.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowired@Qualifier("userDetailsServiceImpl")//需要指定注入的是那個類,避免報錯。private UserDetailsService userDetailsService;@Overridepublic Authentication authenticate(Authentication authentication) {String username = String.valueOf(authentication.getPrincipal());String password = String.valueOf(authentication.getCredentials());UserDetails userDetails = userDetailsService.loadUserByUsername(username);System.out.println("------------->       JwtAuthenticationProvider:"+userDetails.getUsername()+","+userDetails.getPassword());if(userDetails != null && StringUtils.isNotBlank(userDetails.getPassword())&& userDetails.getPassword().equals(password)){return new UsernamePasswordAuthenticationToken(username,password,authentication.getAuthorities());}try {throw new Exception("RespCodeEnum.NAME_OR_PASSWORD_ERROR");} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic boolean supports(Class<?> authentication) {return UsernamePasswordAuthenticationToken.class.equals(authentication);}
}

5.攔截器實(shí)現(xiàn)。

(1)CustomFilter

package com.x.x.x.filter;import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;/*** OncePerRequestFilter 是 Spring Security 提供的一個抽象類,確保在每個請求中只執(zhí)行一次特定的過濾邏輯。* 它是實(shí)現(xiàn)自定義過濾器的基礎(chǔ),通常用于對請求進(jìn)行預(yù)處理或后處理。(實(shí)現(xiàn) JWT 會用到這個接口)* 提供了一種機(jī)制,以確保過濾器的邏輯在每個請求中只執(zhí)行一次,非常適合需要對每個請求進(jìn)行處理的場景。* 通過繼承該類,可以輕松實(shí)現(xiàn)自定義過濾器適合用于記錄日志、身份驗證、權(quán)限檢查等場景。** 本處繼承 OncePerRequestFilter 類,并重寫 doFilterInternal 方法。* 但是需要再spring security配置類中注冊自定義的過濾器*/
public class CustomFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {// 自定義過濾邏輯,例如記錄請求日志System.out.println("Request URI: " + request.getRequestURI());// 繼續(xù)執(zhí)行過濾鏈filterChain.doFilter(request, response);}
}

(2)JwtAuthenticationTokenFilter

package com.x.x.x.filter;import com.x.x.x.dao.BaseUsersDao;
import io.jsonwebtoken.Claims;
import java.io.IOException;import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import com.x.x.x.until.JwtUtil;@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {/***  用于驗證賬號密碼,本處于數(shù)據(jù)庫交互*/@Autowiredprivate BaseUsersDao baseUsersDao;@Autowired@Qualifier("userDetailsServiceImpl")//需要指定注入的是那個類,避免報錯。private UserDetailsService userDetailsService;/*** 重寫了 OncePerRequestFilter 類中的抽象方法 doFilterInternal。* OncePerRequestFilter 是 Spring Security 提供的一個基礎(chǔ)類* ,設(shè)計用來確保過濾器在同一個請求中只執(zhí)行一次。* @param request* @param response* @param filterChain* @throws ServletException* @throws IOException*/@Overrideprotected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {// 獲取請求頭的驗證信息,即前端傳回的tokenString token = request.getHeader("Authorization");System.out.println("----》     JwtAuthenticationTokenFilter,驗證token過濾器,獲取到的token值:"+token);//為空時候繼續(xù)下一步過濾鏈,即進(jìn)行登錄認(rèn)證。后續(xù)進(jìn)行格式驗證,如果以bearer開始去掉前面的前綴if (!StringUtils.hasText(token) ) {System.out.println("----》     JwtAuthenticationTokenFilter,token驗證:"+"token為空!");filterChain.doFilter(request, response);return;}if (token.startsWith("Bearer ")) {System.out.println("----》     JwtAuthenticationTokenFilter,token格式驗證中:"+"token格式以Bearer開頭,去掉開頭!");token = token.substring(7);}//驗證token是否過期boolean isValid = JwtUtil.validateJwtToken(token);//只在util中只驗證是否過期了。if (!isValid) {System.out.println("----》     token驗證失敗,token過期。");response(response, "驗證失敗");return;}//獲取token載荷中的用戶信息Claims claims = JwtUtil.parseClaim(token).getPayload();String userid = claims.get("username").toString();//查詢數(shù)據(jù)庫中用戶信息System.out.println("----》     數(shù)據(jù)庫驗證用戶信息。"+"userid:"+userid);UserDetails userDetails = userDetailsService.loadUserByUsername(userid);System.out.println("----》     數(shù)據(jù)庫中數(shù)據(jù):"+userDetails.getUsername()+","+userDetails.getPassword());//設(shè)置安全上下文//創(chuàng)建一個自定義的 UserDetailsImpl 對象,將查詢到的用戶信息封裝。//創(chuàng)建一個 UsernamePasswordAuthenticationToken 對象,表示用戶的認(rèn)證信息// ,并將其設(shè)置到 Spring Security 的 SecurityContextHolder 中,以便后續(xù)請求能夠訪問到用戶的認(rèn)證信息。UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());// 如果是有效的jwt,那么設(shè)置該用戶為認(rèn)證后的用戶SecurityContextHolder.getContext().setAuthentication(authenticationToken);//繼續(xù)過濾鏈System.out.println("----》     jwt過濾器執(zhí)行完畢!"+authenticationToken);filterChain.doFilter(request, response);}private void response(@NotNull HttpServletResponse response,String error) throws IOException {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 或者使用自定義狀態(tài)碼response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding("UTF-8");response.getWriter().write("{\n" +"  \"states\": \""+error+"\",\n" +"  \"message\": \"無效token!\"\n" +"}");}}

6.jwt實(shí)現(xiàn)

package com.x.x.x.until;import com.x.x.x.enums.BaseInfoEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import org.springframework.stereotype.Component;import javax.crypto.SecretKey;
import java.time.Instant;
import java.util.*;// @Component將這個類標(biāo)記為 Spring 組件,允許 Spring 管理該類的生命周期,便于依賴注入。
@Component
public class JwtUtil {/*** 過期時間(單位:秒),4小時為14400s*/public static final int ACCESS_EXPIRE = Integer.parseInt(BaseInfoEnum.fiedIdOf("access_expire").getFiedIdInfo());//14400;/*** 加密算法*/private final static SecureDigestAlgorithm<SecretKey, SecretKey> ALGORITHM = Jwts.SIG.HS256;/*** 私鑰 / 生成簽名的時候使用的秘鑰secret,一般可以從本地配置文件中讀取,切記這個秘鑰不能外露,只在服務(wù)端使用,在任何場景都不應(yīng)該流露出去。* 一旦客戶端得知這個secret, 那就意味著客戶端是可以自我簽發(fā)jwt了。* 應(yīng)該大于等于 256位(長度32及以上的字符串),并且是隨機(jī)的字符串*/private final static String SECRET = BaseInfoEnum.fiedIdOf("secret").getFiedIdInfo();//"Cpj2cc09BRTstcISP5HtEAMxwuFEh-nJiL1mppdsz8k@lzgs";/*** 秘鑰實(shí)例,相比secretkeyspec方法base64編碼指定驗證方式,該種方式更加簡便安全。*/public static final SecretKey KEY = Keys.hmacShaKeyFor(SECRET.getBytes());/*** jwt簽發(fā)者*/private final static String JWT_ISS = BaseInfoEnum.fiedIdOf("jwt_iss").getFiedIdInfo();/*** jwt主題*/private final static String SUBJECT = "Peripherals";/*** jwt構(gòu)建器,生成token* 這些是一組預(yù)定義的聲明,它們 不是強(qiáng)制性的,而是推薦的 ,以 提供一組有用的、可互操作的聲明 。* iss: jwt簽發(fā)者* sub: jwt所面向的用戶* aud: 接收jwt的一方* exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間* nbf: 定義在什么時間之前,該jwt都是不可用的.* iat: jwt的簽發(fā)時間* jti: jwt的唯一身份標(biāo)識,主要用來作為一次性token,從而回避重放攻擊*/public static String genAccessToken(String username ,String roleId,String company) {// 令牌idString uuid = UUID.randomUUID().toString();Date exprireDate = Date.from(Instant.now().plusSeconds(ACCESS_EXPIRE));//System.out.println("key:"+KEY);return Jwts.builder()// 設(shè)置頭部信息header.header().add("typ", "JWT").add("alg", "HS256").and()// 設(shè)置自定義負(fù)載信息payload.claim("username", username )//.claim("roleId",roleId ).claim("company",company )// 令牌ID.id(uuid)// 過期日期.expiration(exprireDate)// 簽發(fā)時間.issuedAt(new Date())// 主題.subject(SUBJECT)// 簽發(fā)者.issuer(JWT_ISS)// 簽名.signWith(KEY, ALGORITHM).compact();}/*** 解析token* @param token token* @return Jws<Claims>*/public static Jws<Claims> parseClaim(String token) {return Jwts.parser().verifyWith(KEY).build().parseSignedClaims(token);}/*** 獲取頭部信息* @param token* @return*/public static JwsHeader parseHeader(String token) {return parseClaim(token).getHeader();}/*** 獲取載荷信息* @param token* @return*/public static Claims parsePayload(String token) {return parseClaim(token).getPayload();}/*** token驗證,token是否過期正確* @param token* @return*/public static boolean validateJwtToken(String token) {try {// 解析 Token,驗證簽名。驗證載荷Claims claims = parseClaim(token).getPayload();//System.out.println("content:---"+claims.get("username"));// 驗證聲明(例如過期時間)if (claims.getExpiration().before(new Date())) {System.out.println("Token has expired.");return false;}// 在這里可以進(jìn)行其他自定義驗證// 例如檢查用戶角色、權(quán)限等// Token 驗證通過return true;} catch (Exception e) {// 驗證失敗System.out.println("Token validation failed: " + e.getMessage());return false;}}/*** 直接獲取到載荷的具體內(nèi)容* @param token* @return*/public static Map<String, Object> token2userInfo(String token){Map<String, Object> tokenMap = new HashMap<String, Object>();Claims claims = parseClaim(token).getPayload();tokenMap.put("company", claims.get("company"));tokenMap.put("loginName", claims.get("username"));tokenMap.put("roleId", claims.get("roleId"));return tokenMap;}//測試public static void main(String[] args){String token = genAccessToken("123","admin","123");System.out.println("token:"+token);boolean isValid = validateJwtToken(token);System.out.println(isValid);System.out.println(parseHeader(token));System.out.println(parsePayload(token));}}

7.接口實(shí)現(xiàn)

/*** 用戶登錄接口。* 本處調(diào)用spring security驗證功能。(但本項目是前后端分離的,禁用了security登錄頁功能,* 因為其重定向默認(rèn)只能用“GET”方式請求)* @param request* @return* @throws Exception*/@PostMapping("/login")public Map<String, Object> login(HttpServletRequest request) throws Exception{Map<String, Object> modelMap = new HashMap<String, Object>();request.setCharacterEncoding("UTF8");//設(shè)置request獲取數(shù)據(jù)的編碼方式為utf-8String loginName = HttpServletRequestUtil.getString(request, "loginName");String password = HttpServletRequestUtil.getString(request, "password");if (loginName ==null || loginName.isBlank()  || password == null || password.isBlank()){modelMap.put("success", false);modelMap.put("msg", "用戶名和密碼均不能為空");logger.error("---->    登錄失敗,用戶名和密碼為空!");return modelMap;}//認(rèn)證設(shè)置,在后續(xù)的方法中,已經(jīng)設(shè)置了連接數(shù)據(jù)庫認(rèn)證loadUserByUsername//先設(shè)置認(rèn)證authentication  這一步Authenticated=falseUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginName, password);//自動調(diào)用loadUserByUsername驗證用戶名和密碼,從數(shù)據(jù)庫中對比查找,如果找到了會返回一個帶有認(rèn)證的封裝后的用戶,否則會報錯,自動處理。(這里我們假設(shè)我們配置的security是基于數(shù)據(jù)庫查找的)try{Authentication authenticate = authenticationManager.authenticate(authenticationToken);SecurityContextHolder.getContext().setAuthentication(authenticate);String token = genAccessToken(loginName,"admin","123");modelMap.put("token",token);modelMap.put("success", true);return modelMap;} catch (Exception e) {modelMap.put("success", false);modelMap.put("msg", "用戶名或密碼錯誤");logger.error("---->    登錄失敗,用戶名或密碼錯誤!");return modelMap;}}

這里需要注意:

1.一般是url請求帶token,直接驗證token,通過則授權(quán),在過濾器JwtAuthenticationTokenFilter中UsernamePasswordAuthenticationToken authenticationToken =
? ? ? ? ? ? ? ? new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());? 驗證結(jié)果是true的。

2.不帶token則在控制器中對用戶密碼進(jìn)行驗證,因為在loadUserByUsername方法中設(shè)置了對用戶名密碼的驗證,所以使用UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginName, password);后,需要手動使用?Authentication authenticate = authenticationManager.authenticate(authenticationToken);進(jìn)行驗證,驗證通過則驗證結(jié)果是true的。

http://www.risenshineclean.com/news/60114.html

相關(guān)文章:

  • 自己做網(wǎng)站系統(tǒng)首選平臺域名解析ip地址
  • 模板網(wǎng)站建設(shè)優(yōu)惠青島seo
  • 福建省建筑信息平臺上海怎么做seo推廣
  • 網(wǎng)站怎么做二級頁面寧波seo托管公司
  • 抽獎的網(wǎng)站怎么做今日熱搜榜前十名
  • 網(wǎng)站建設(shè)與網(wǎng)頁制作教程流程優(yōu)化四個方法
  • 個人網(wǎng)站做重定向圖片網(wǎng)站怎么添加外鏈
  • 蕪湖市網(wǎng)站建設(shè)站長工具外鏈查詢
  • 永久免費(fèi)網(wǎng)站空間北京突發(fā)重大消息
  • wordpress頁面都在seo軟件資源
  • 開發(fā)公司英文企業(yè)站seo
  • javascript做網(wǎng)站重要嗎網(wǎng)絡(luò)營銷公司網(wǎng)絡(luò)推廣
  • 如何建設(shè)數(shù)據(jù)庫搜索網(wǎng)站常用搜索引擎有哪些
  • 南寧seo網(wǎng)站排名優(yōu)化公司百度愛采購官方網(wǎng)站
  • 如何在360做網(wǎng)站SEO百度引流推廣費(fèi)用多少
  • 做花生的網(wǎng)站江蘇做網(wǎng)站的公司有哪些
  • 淘寶網(wǎng)站代理怎么做的網(wǎng)站服務(wù)器ip查詢
  • wordpress如何設(shè)置在某一分類目錄下的文章都顯示特定小工具seo關(guān)鍵詞排名優(yōu)化推薦
  • 獨(dú)立站有哪些常見平臺手機(jī)制作網(wǎng)站的軟件
  • web開發(fā)不只是做網(wǎng)站企業(yè)網(wǎng)站建設(shè)流程
  • 網(wǎng)站超級推廣seo單詞優(yōu)化
  • 免費(fèi)建立手機(jī)網(wǎng)站嗎長沙sem培訓(xùn)
  • 學(xué)校網(wǎng)站logo怎么做推廣平臺都有哪些
  • 云優(yōu)化網(wǎng)站建設(shè)seo有什么作用
  • 西安網(wǎng)址開發(fā) 網(wǎng)站制作一個網(wǎng)站推廣
  • 潮牌衣服網(wǎng)站建設(shè)可行性分析常用的seo查詢工具
  • 溫州建設(shè)工程信息網(wǎng)站seo優(yōu)化按天扣費(fèi)
  • 用vs做網(wǎng)站表格向上居中zac博客seo
  • 南昌網(wǎng)站建設(shè)那家好一個新產(chǎn)品怎么推廣
  • 貴陽app定制開發(fā)鄭州seo優(yōu)化外包顧問阿亮