登錄功能實現深度解析:從會話管理到安全校驗全流程指南

登錄功能實現深度解析:從會話管理到安全校驗全流程指南

大家好,我是凱哥Java

本文標簽:登錄驗證流程、過濾器與攔截器、安全防護措施

image.png

簡介

本文深入探討了從登錄功能實現到會話管理和安全校驗的全流程,包括參數校驗、身份驗證、令牌生成和存儲等關鍵步驟。通過比較主流的會話技術(如Cookie、Session和JWT),并詳細講解過濾器與攔截器的區別及其應用場景,提供了構建高性能、高安全性Web應用的具體指導。

一、登錄功能核心實現流程

1.1 登錄流程圖解

image.png

1.2 關鍵實現步驟

  • 參數校驗層:驗證用戶名/郵箱格式、密碼強度

  • 身份驗證層:數據庫查詢+密碼哈希比對

  • 令牌生成層:使用JWT生成訪問令牌和刷新令牌

  • 令牌存儲層:Redis緩存令牌實現快速驗證

  • 安全傳輸層:HTTPS+HttpOnly Cookie保障傳輸安全

二、會話跟蹤技術深度對比

2.1 主流會話技術對比

技術類型CookieSessionJWT
存儲位置客戶端服務端客戶端
安全性較低較高較高(需HTTPS)
擴展性單域限制集群部署需同步天然支持分布式
性能開銷中等
典型應用場景簡單狀態保持傳統Web應用前后端分離/移動端

2.2 JWT令牌技術詳解

令牌結構示例

// Header

{

? "alg": "HS256",

? "typ": "JWT"

}

// Payload

{

? "sub": "1234567890",

? "name": "John Doe",

? "iat": 1516239022,

? "exp": 1516242622

}

// Signature

HMACSHA256(

? base64UrlEncode(header) + "." +

? base64UrlEncode(payload),

? secret)

Java生成JWT示例

public String generateToken(UserDetails userDetails) {

? ? Map<String, Object> claims = new HashMap<>();

? ? claims.put("roles", userDetails.getAuthorities());

? ??

? ? return Jwts.builder()

? ? ? ? .setClaims(claims)

? ? ? ? .setSubject(userDetails.getUsername())

? ? ? ? .setIssuedAt(new Date(System.currentTimeMillis()))

? ? ? ? .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))

? ? ? ? .signWith(SignatureAlgorithm.HS256, secretKey)

? ? ? ? .compact();

}

三、安全校驗實現方案

3.1 過濾器(Filter)實現方案

public class JwtFilter implements Filter {

? ? @Override

? ? public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)?

? ? ? ? throws IOException, ServletException {

? ? ? ??

? ? ? ? HttpServletRequest request = (HttpServletRequest) req;

? ? ? ? String token = resolveToken(request);

? ? ? ??

? ? ? ? if (StringUtils.hasText(token) && validateToken(token)) {

? ? ? ? ? ? Authentication auth = parseAuthentication(token);

? ? ? ? ? ? SecurityContextHolder.getContext().setAuthentication(auth);

? ? ? ? }

? ? ? ??

? ? ? ? chain.doFilter(req, res);

? ? }

? ? private String resolveToken(HttpServletRequest request) {

? ? ? ? String bearerToken = request.getHeader("Authorization");

? ? ? ? if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {

? ? ? ? ? ? return bearerToken.substring(7);

? ? ? ? }

? ? ? ? return null;

? ? }

}

3.2 攔截器(Interceptor)實現方案

public class JwtInterceptor implements HandlerInterceptor {

? ??

? ? @Override

? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)?

? ? ? ? throws Exception {

? ? ? ??

? ? ? ? if (!(handler instanceof HandlerMethod)) return true;

? ? ? ? String token = getTokenFromRequest(request);

? ? ? ? if (token == null || !jwtProvider.validateToken(token)) {

? ? ? ? ? ? throw new AuthenticationException("Invalid JWT token");

? ? ? ? }

? ? ? ??

? ? ? ? setAuthentication(token);

? ? ? ? return true;

? ? }

? ? private String getTokenFromRequest(HttpServletRequest request) {

? ? ? ? // 從Cookie或Header獲取令牌

? ? }

}

3.3 過濾器與攔截器對比

image.png

四、全局異常處理機制

4.1 異常處理類實現

@RestControllerAdvice

public class GlobalExceptionHandler {

? ??

? ? @ExceptionHandler(AuthenticationException.class)

? ? public ResponseEntity<ErrorResponse> handleAuthException(AuthenticationException ex) {

? ? ? ? ErrorResponse error = new ErrorResponse();

? ? ? ? error.setStatus(HttpStatus.UNAUTHORIZED.value());

? ? ? ? error.setMessage("Authentication failed: " + ex.getMessage());

? ? ? ? error.setTimestamp(LocalDateTime.now());

? ? ? ? return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);

? ? }

? ? @ExceptionHandler(AccessDeniedException.class)

? ? public ResponseEntity<ErrorResponse> handleAccessDenied(AccessDeniedException ex) {

? ? ? ? ErrorResponse error = new ErrorResponse();

? ? ? ? error.setStatus(HttpStatus.FORBIDDEN.value());

? ? ? ? error.setMessage("Access denied: " + ex.getMessage());

? ? ? ? return new ResponseEntity<>(error, HttpStatus.FORBIDDEN);

? ? }

}

4.2 錯誤響應DTO

@Data

@AllArgsConstructor

@NoArgsConstructor

public class ErrorResponse {

? ? private int status;

? ? private String message;

? ? private LocalDateTime timestamp;

? ? private String path;

? ??

? ? public ErrorResponse(HttpStatus status, String message, String path) {

? ? ? ? this.status = status.value();

? ? ? ? this.message = message;

? ? ? ? this.timestamp = LocalDateTime.now();

? ? ? ? this.path = path;

? ? }

}

五、安全增強最佳實踐

5.1 令牌刷新機制

public TokenPair refreshToken(String refreshToken) {

? ? if (!validateRefreshToken(refreshToken)) {

? ? ? ? throw new InvalidTokenException("Invalid refresh token");

? ? }

? ??

? ? String username = parseUsername(refreshToken);

? ? UserDetails user = userService.loadUserByUsername(username);

? ??

? ? String newAccessToken = generateAccessToken(user);

? ? String newRefreshToken = generateRefreshToken(user);

? ??

? ? redisTemplate.delete(refreshToken);

? ? redisTemplate.opsForValue().set(newRefreshToken, username, REFRESH_EXPIRE);

? ??

? ? return new TokenPair(newAccessToken, newRefreshToken);

}

5.2 并發登錄控制

public void handleConcurrentLogin(String username, String newSessionId) {

? ? String oldSession = redisTemplate.opsForValue().get("user:" + username);

? ? if (StringUtils.hasText(oldSession)) {

? ? ? ? // 1. 發送下線通知

? ? ? ? messagingTemplate.convertAndSendToUser(oldSession, "/queue/logout", "forced_logout");

? ? ? ? // 2. 清除舊令牌

? ? ? ? redisTemplate.delete(oldSession);

? ? }

? ? // 3. 存儲新會話

? ? redisTemplate.opsForValue().set("user:" + username, newSessionId);

}

六、性能優化方案

6.1 令牌驗證優化

public boolean validateToken(String token) {

? ? // 先檢查黑名單

? ? if (redisTemplate.hasKey("token:blacklist:" + token)) {

? ? ? ? return false;

? ? }

? ??

? ? // 快速過期檢查

? ? if (Jwts.parser().parseClaimsJws(token).getBody().getExpiration().before(new Date())) {

? ? ? ? return false;

? ? }

? ??

? ? // 詳細驗證

? ? try {

? ? ? ? Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);

? ? ? ? return true;

? ? } catch (JwtException e) {

? ? ? ? return false;

? ? }

}

6.2 緩存策略設計

@Cacheable(value = "userDetails", key = "#username")

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

? ? User user = userRepository.findByUsername(username)

? ? ? ? .orElseThrow(() -> new UsernameNotFoundException("User not found"));

? ??

? ? return new CustomUserDetails(

? ? ? ? user.getUsername(),

? ? ? ? user.getPassword(),

? ? ? ? getAuthorities(user.getRoles())

? ? );

}

@CacheEvict(value = "userDetails", key = "#user.username")

public void updateUser(User user) {

? ? userRepository.save(user);

}

七、安全防護措施

7.1 常見攻擊防護

image.png

7.2 安全頭配置

@Configuration

public class SecurityHeaderConfig implements WebMvcConfigurer {

? ??

? ? @Override

? ? public void addCorsMappings(CorsRegistry registry) {

? ? ? ? registry.addMapping("/**")

? ? ? ? ? ? .allowedOrigins("https://yourdomain.com")

? ? ? ? ? ? .allowedMethods("GET", "POST")

? ? ? ? ? ? .allowCredentials(true);

? ? }

? ? @Bean

? ? public FilterRegistrationBean<HeaderFilter> securityHeadersFilter() {

? ? ? ? FilterRegistrationBean<HeaderFilter> registration = new FilterRegistrationBean<>();

? ? ? ? registration.setFilter(new HeaderFilter());

? ? ? ? registration.addUrlPatterns("/*");

? ? ? ? return registration;

? ? }

? ? private static class HeaderFilter extends OncePerRequestFilter {

? ? ? ? @Override

? ? ? ? protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,?

? ? ? ? ? ? FilterChain filterChain) throws ServletException, IOException {

? ? ? ? ? ??

? ? ? ? ? ? response.setHeader("X-Content-Type-Options", "nosniff");

? ? ? ? ? ? response.setHeader("X-Frame-Options", "DENY");

? ? ? ? ? ? response.setHeader("X-XSS-Protection", "1; mode=block");

? ? ? ? ? ? response.setHeader("Content-Security-Policy", "default-src 'self'");

? ? ? ? ? ??

? ? ? ? ? ? filterChain.doFilter(request, response);

? ? ? ? }

? ? }

}

八、監控與日志

8.1 登錄審計日志

@Aspect

@Component

public class LoginAuditAspect {

? ??

? ? @Autowired

? ? private AuditLogService auditLogService;

? ? @AfterReturning(pointcut = "execution(* AuthController.login(..))", returning = "result")

? ? public void logSuccessLogin(JoinPoint joinPoint, Object result) {

? ? ? ? Object[] args = joinPoint.getArgs();

? ? ? ? String username = (String) args[0];

? ? ? ? auditLogService.log(username, "LOGIN_SUCCESS", "User logged in successfully");

? ? }

? ? @AfterThrowing(pointcut = "execution(* AuthController.login(..))", throwing = "ex")

? ? public void logFailedLogin(JoinPoint joinPoint, Exception ex) {

? ? ? ? Object[] args = joinPoint.getArgs();

? ? ? ? String username = (String) args[0];

? ? ? ? auditLogService.log(username, "LOGIN_FAILED", ex.getMessage());

? ? }

}

8.2 監控指標

@Configuration

public class SecurityMetricsConfig {

? ? @Bean

? ? public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {

? ? ? ? return registry -> registry.config().commonTags(

? ? ? ? ? ? "application", "auth-service",

? ? ? ? ? ? "region", System.getenv("REGION")

? ? ? ? );

? ? }

? ? @Bean

? ? public TimedAspect timedAspect(MeterRegistry registry) {

? ? ? ? return new TimedAspect(registry);

? ? }

? ? @Bean

? ? public Counter loginAttemptCounter(MeterRegistry registry) {

? ? ? ? return Counter.builder("auth.login.attempts")

? ? ? ? ? ? .description("Total login attempts")

? ? ? ? ? ? .register(registry);

? ? }

}

九、總結與選型建議

9.1 技術選型矩陣

image.png

9.2 性能優化checklist

  • 啟用JWT壓縮(特別是包含大量claims時)

  • 使用非對稱加密算法(RS256)替代HS256

  • 實現令牌黑名單的自動過期清理

  • 配置合理的會話超時時間

  • 啟用HTTP/2提升傳輸效率

  • 使用CDN加速靜態資源訪問

通過本文的詳細實現方案,大家可以構建出更加安全可靠、高性能的登錄認證系統。建議根據實際業務需求選擇合適的會話管理方案,并持續監控系統安全指標。

  1. JWT令牌生成指南

  2. Redis在會話管理中的作用

  3. Spring Security過濾器配置

  4. Web應用常見攻擊防御策略

  5. 基于OAuth2的微服務認證

作者:凱哥Java

日期:2025年07月17日

標簽:登錄驗證流程、令牌管理與安全、會話跟蹤技術、過濾器與攔截器、安全防護措施

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89540.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89540.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89540.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2023 年 5 月青少年軟編等考 C 語言六級真題解析

目錄 T1. 字符串插入 思路分析 T2. 機器翻譯 思路分析 T3. 棧基本操作 思路分析 T4. 雙端隊列 思路分析 T1. 字符串插入 題目鏈接:SOJ D1138 有兩個字符串 s t r str str 和 s u b s t r substr substr, s t r str str 的字符個數不超過 10 10 10, s u b s t r substr …

Redux架構解析:狀態管理的核心原理

Redux 作為 JavaScript 應用的狀態管理庫&#xff0c;其技術架構與核心原理圍繞??可預測的狀態管理??設計&#xff0c;通過嚴格的單向數據流和函數式編程理念實現復雜應用的狀態控制。以下從設計理念、核心架構、工作流程、源碼實現等角度進行系統性剖析&#xff1a;一、設…

linux制作鏡像、壓縮鏡像、燒錄的方法

最近在玩香橙派的時候&#xff0c;需要搞多個板子&#xff0c;一個一個配環境也太麻煩了吧......于是通過搜索&#xff0c;發現可以把linux設備&#xff08;比如香橙派&#xff0c;樹莓派等等&#xff09;制作為鏡像&#xff0c;然后像燒錄官方鏡像一樣燒進新的sd卡&#xff0c…

機械材料計算軟件,快速核算重量

軟件介紹 今天為大家推薦一款專為機械行業設計人員打造的金屬材料重量計算軟件&#xff0c;幫助工程師快速完成材料重量核算。 軟件特點 這款綠色版計算工具體積小巧&#xff0c;不足100KB&#xff0c;無需安裝即可直接運行&#xff0c;不占用系統資源&#xff0c;特別適…

Chrome更新后,擴展不能用問題

Chrome更新后&#xff0c;擴展不能用問題 此擴展程序不再受支持&#xff0c;因此已停用 在 Windows 10/11 搜索框中輸入 regedit 打開 注冊表編輯器 在注冊表編輯器中打開&#xff1a;HKEYLOCALMACHINE\SOFTWARE\Policies\ 右鍵單擊 Policies 新建項 命名為 Google 右鍵單…

【Python】通過cmd的shell命令獲取局域網內所有IP、MAC地址,通過主機名獲取IP

【Python】通過cmd的shell命令獲取局域網內所有IP、MAC地址&#xff0c;通過主機名獲取IP 更新以gitee為準&#xff1a; gitee 文章目錄cmd命令獲取IPping主機名獲取IP的主機名socket獲取當前網關運行效果附錄&#xff1a;列表的賦值類型和py打包列表賦值BUG復現代碼改進優化總…

sky-take-out項目Mybatis的使用

分頁查詢public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {PageHelper.startPage(categoryPageQueryDTO.getPage(),categoryPageQueryDTO.getPageSize());//下一條sql進行分頁&#xff0c;自動加入limit關鍵字分頁Page<Category> page categor…

H3CNE小小綜合實驗

實驗拓撲圖實驗需求 按照圖示配置IP地址在SW1和SW2之間配置鏈路聚合增加鏈路帶寬&#xff0c;提高可靠性PC5和PC6屬于VLAN10&#xff0c; PC7和PC8屬于VLAN20SW1和SW2屬于二層交換機&#xff0c;SW3為三層交換機&#xff08;VLAN100用于對接R4&#xff09;,在交換機之間相連的鏈…

IP協議深入理解

一、什么是ip協議?1.1、ip協議是網絡層協議&#xff0c;ip協議的本質工作是提供一種能力&#xff0c;把數據可靠的跨網絡從主機A送到主機B&#xff1b;1.2、什么是ip&#xff1f;ip目標網絡目標主機&#xff1b;畫圖圖解:如圖&#xff0c;當主機A想要把數據發給主機B時&#x…

接收表單數據:serialize()函數解析

一、form-serialize作用與引入 作用&#xff1a; form-serialize可以快速收集表單數據&#xff0c;按照使用者意愿轉化為對象或字符串輸出&#xff0c;以便于提交至服務器。 引入&#xff1a; form-serialize不是瀏覽器自帶的JS方法&#xff0c;而是第三方工具庫。可以直接通過…

vc配置使用預編譯

預編譯原理 stdafx.h中加入系統文件&#xff0c;減少cpp中對這些文件的解析&#xff0c;提高速度 stdafx.h 會把編譯的文件生成pch&#xff0c;后續解析頭文件直接調用pch里面的數據 配置 新建stdafx.h和stdafx.cpp文件 配置stdafx.cpp文件為/Yc 創建預編譯文件整個項目設置/Yc…

反射機制的登錄系統

一、實體層&#xff08;po層&#xff09; //UserInfo package com.hugeyurt.po;import java.sql.ResultSet; import java.sql.SQLException;public class UserInfo {private String userID;private String name;private int count;private Long errorTime;private String pwd;p…

裝飾器模式及優化

裝飾器模式&#xff08;Decorator Pattern&#xff09;是一種結構型設計模式&#xff0c;它允許向一個現有的對象添加新的功能&#xff0c;同時又不改變其結構。這種模式創建了一個裝飾器類&#xff0c;用來包裝原有的類&#xff0c;并在保持類方法簽名完整性的前提下&#xff…

共指消解技術全解析:從語言學規則到深度學習(附論文精讀)

精讀威斯康星大學綜述《Coreference Resolution: A Survey》&#xff0c;揭秘NLP中"實體鏈接"的核心技術一、什么是共指消解&#xff1f;為什么它是NLP的基石&#xff1f;共指消解(Coreference Resolution) 旨在識別文本中指向同一實體的不同表述。例如&#xff1a;t…

git配置git commit -m “fix 11,22: 修改bugid為11,22“

文章目錄前言一、報錯提示二、實現1.commitlint.config.js規范配置2. **修改正則表達式**&#xff1a;3. **移除 scope-case 規則**&#xff1a;4. **增強自定義規則邏輯**&#xff1a;測試結果&#xff1a;正則表達式詳解&#xff1a;前言 提示&#xff1a;正常的配置git規范…

nastools繼任者?極空間部署影視自動化訂閱系統『MediaMaster』

nastools繼任者&#xff1f;極空間部署影視自動化訂閱系統『MediaMaster』 哈嘍小伙伴們好&#xff0c;我是Stark-C~ 對于我們NAS玩家來說&#xff0c;觀影總是大家繞不開的一個執念&#xff0c;并且為觀影的折騰大家也都是樂此不疲~ 曾經有一個非常絕絕子的觀影神器擺在我們…

題解:CF1690G Count the Trains

思路&#xff1a; 首先我們可以理清一下各種情況&#xff1a;1&#xff09;m可能為02&#xff09;一次操作時&#xff0c;只需要考慮每節火車的車頭。3&#xff09;當一節火車的速度降低時&#xff0c;只會影響它及它后面的車廂當m0時&#xff0c;我們可以記錄上一節車頭的速度…

CCF編程能力等級認證GESP—C++3級—20250628

CCF編程能力等級認證GESP—C3級—20250628單選題&#xff08;每題 2 分&#xff0c;共 30 分&#xff09;判斷題&#xff08;每題 2 分&#xff0c;共 20 分&#xff09;編程題 (每題 25 分&#xff0c;共 50 分)奇偶校驗分糖果單選題&#xff08;每題 2 分&#xff0c;共 30 分…

2G和3G網絡關閉/退網狀態(截止2025年7月)

從能打語音電話的2G&#xff0c;到能發彩信、聊QQ的3G&#xff0c;這兩項陪伴了我們數十年的通信技術&#xff0c;正在悄然退出歷史舞臺。近日&#xff0c;全球移動供應商協會&#xff08;GSA&#xff09;發布的《2025年7月2G和3G網絡關閉報告》顯示&#xff0c;全球已有超百個…

Day06_C語言網絡編程20250718mobus重點

01.思維導圖1 什么是 modbus他是一個在工控領域非常好用的通信寫 modbus協議本質上是一個 基于 tcp 協議二次封裝的一個協議 什么叫做基于tcp二次封裝的協議&#xff1a;我們自己寫的pack_t(無論靜態還是動態)&#xff0c;都是屬于二次封裝的協議modbus協議是一種 “主從問答式…