SpringBoot+SpringSecurity實現(xiàn)認證的流程詳解
整合springSecurity
對應springboot版本,直接加依賴,這樣版本不會錯
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
比如我這里是2.6.4的版本。對應的springSecurity版本是5.6.x
沒找到springSecurity對應springboot依賴對應表
但springboot2.x基本對應security的5.x版本
3.x對應6.x版本
最基本的概念:
認證和授權
- 認證(Authentication):用戶輸入賬戶密碼,系統(tǒng)讓其登錄到系統(tǒng)里
- 授權(authorities):用戶的權限不同,他們能在系統(tǒng)做的事情都不同
springSecurity如何實現(xiàn)認證
UsernamePasswordAuthenticationToken可以允許你傳入username和password參數(shù)
關鍵代碼
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
然后調(diào)用UserDetailsService的loadUserByUsername方法根據(jù)username查出數(shù)據(jù)庫中的這個用戶
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //查詢用戶信息 User user = userMapper.findByColumnAndValue("user_name", username); if(user==null){ throw new UsernameNotFoundException("用戶名或密碼錯誤"); } //查詢用戶權限 List<String> perms = menuMapper.selectPermsByUserId(user.getId()); return new LoginUser(user,perms); }
然后可以調(diào)用authenticationManager.authenticate方法對用戶輸入的賬號密碼進行驗證,密碼會經(jīng)過passwordEncoder去加密,然后和數(shù)據(jù)庫中該用戶的賬號密碼比對。
//加密器 bean @Bean public PasswordEncoder PasswordEncoder(){ return new BCryptPasswordEncoder(); } //驗證邏輯 Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
如果通過,返回一個Authentication對象,封裝了該用戶的信息。像這樣:
這時需要將信息保存到Security上下文。
像這樣:
SecurityContextHolder.getContext().setAuthentication(authenticate);
這樣,后面的代碼就可以通過SecurityContextHolder.getContext()來獲取當前用戶了。
如果失敗,springSecurity會拋出一個異常:AuthenticationException。
框架有默認異常處理器,但一般你可以自定義異常處理器,并把錯誤信息和業(yè)務整合。像這樣:
@Component public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { ResponseResult<Object> noAuthentication = ResponseResult.noAuthentication("認證失敗"); String json = JSON.toJSONString(noAuthentication); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Cache-Control","no-cache"); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); response.getWriter().println(json); response.getWriter().flush(); } }
其他接口如何校驗用戶是否登錄
需要一個檢查登錄過濾器,這個過濾器要通過檢查token,并解析出用戶信息,保存到Security上下文
@Component public class CheckLoginFilter extends OncePerRequestFilter { @Autowired private UserMapper userMapper; @Autowired private RedisCache redisCache; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 如果請求路徑是登錄接口,直接放行 String requestURI = request.getRequestURI(); if ("/user/login".equals(requestURI)) { filterChain.doFilter(request, response); return; } ? //獲取token String token = request.getHeader("token"); if(token==null){ //springSecurity有一個過濾器會自動檢查Context有沒有認證 throw new RuntimeException("token為空"); } //解析token,獲取userId Claims claims = JwtUtils.parserClaimsFromToken(token); if(claims==null){ throw new RuntimeException("token非法"); } //從redis數(shù)據(jù)庫里取 Long userId = claims.get("userId", Long.class); String redisKey="login:"+userId; LoginUser loginUser = (LoginUser) redisCache.getCacheObject(redisKey); if(loginUser==null){ throw new RuntimeException("沒有登錄:redis沒有登錄key"); } //todo 從數(shù)據(jù)庫查該用戶的權限,先寫死 //將用戶信息存入Authentication //權限存入,全局設置為該請求已經(jīng)認證過 UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); //checkLogin完成,放行 filterChain.doFilter(request,response); ? } }
基本流程圖
以上就是SpringBoot+SpringSecurity實現(xiàn)認證的流程詳解的詳細內(nèi)容,更多關于SpringBoot SpringSecurity認證流程的資料請關注腳本之家其它相關文章!
相關文章
Spring內(nèi)存緩存Caffeine的基本使用教程分享
Caffeine作為當下本地緩存的王者被大量的應用再實際的項目中,可以有效的提高服務吞吐率、qps,降低rt,本文就來簡單介紹下Caffeine的使用姿勢吧2023-03-03Java轉換流(InputStreamReader/OutputStreamWriter)的使用
本文主要介紹了Java轉換流(InputStreamReader/OutputStreamWriter)的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-01-01Java 如何將網(wǎng)絡資源url轉化為File文件
這篇文章主要介紹了Java 如何將網(wǎng)絡資源url轉化為File文件的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09詳解java如何實現(xiàn)帶RequestBody傳Json參數(shù)的GET請求
在調(diào)試Fate平臺時,遇到了一個奇葩的接口類型,該接口為Get方式,入?yún)⑹且粋€json類型在body中傳遞,使用body中傳參的話為什么不用POST請求而使用了GET請求,下面我們就來深入研究一下2024-02-02