日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

自定义request_Spring Security 自定义登录认证(二)

發布時間:2025/4/16 javascript 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义request_Spring Security 自定义登录认证(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

本篇文章將講述Spring Security自定義登錄認證校驗用戶名、密碼,自定義密碼加密方式,以及在前后端分離的情況下認證失敗或成功處理返回json格式數據

溫馨小提示:Spring Security中有默認的密碼加密方式以及登錄用戶認證校驗,但小編這里選擇自定義是為了方便以后業務擴展,比如系統默認帶一個超級管理員,當認證時識別到是超級管理員賬號登錄訪問時給它賦予最高權限,可以訪問系統所有api接口,或在登錄認證成功后存入token以便用戶訪問系統其它接口時通過token認證用戶權限等

Spring Security入門學習可參考之前文章:

SpringBoot集成Spring Security入門體驗(一)

二、Spring Security 自定義登錄認證處理

基本環境

  • spring-boot 2.1.8
  • mybatis-plus 2.2.0
  • mysql
  • maven項目
  • 數據庫用戶信息表t_sys_user

    案例中關于對該t_sys_user用戶表相關的增刪改查代碼就不貼出來了,如有需要可參考文末提供的案例demo源碼

    1、Security 核心配置類

    配置用戶密碼校驗過濾器

    @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 用戶密碼校驗過濾器*/private final AdminAuthenticationProcessingFilter adminAuthenticationProcessingFilter;public SecurityConfig(AdminAuthenticationProcessingFilter adminAuthenticationProcessingFilter) {this.adminAuthenticationProcessingFilter = adminAuthenticationProcessingFilter;}/*** 權限配置* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.antMatcher("/**").authorizeRequests();// 禁用CSRF 開啟跨域http.csrf().disable().cors();// 登錄處理 - 前后端一體的情況下 // registry.and().formLogin().loginPage("/login").defaultSuccessUrl("/").permitAll() // // 自定義登陸用戶名和密碼屬性名,默認為 username和password // .usernameParameter("username").passwordParameter("password") // // 異常處理 // .failureUrl("/login/error").permitAll() // // 退出登錄 // .and().logout().permitAll();// 標識只能在 服務器本地ip[127.0.0.1或localhost] 訪問`/home`接口,其他ip地址無法訪問registry.antMatchers("/home").hasIpAddress("127.0.0.1");// 允許匿名的url - 可理解為放行接口 - 多個接口使用,分割registry.antMatchers("/login", "/index").permitAll();// OPTIONS(選項):查找適用于一個特定網址資源的通訊選擇。 在不需執行具體的涉及數據傳輸的動作情況下, 允許客戶端來確定與資源相關的選項以及 / 或者要求, 或是一個服務器的性能registry.antMatchers(HttpMethod.OPTIONS, "/**").denyAll();// 自動登錄 - cookie儲存方式registry.and().rememberMe();// 其余所有請求都需要認證registry.anyRequest().authenticated();// 防止iframe 造成跨域registry.and().headers().frameOptions().disable();// 自定義過濾器認證用戶名密碼http.addFilterAt(adminAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class);} }

    2、自定義用戶密碼校驗過濾器

    @Slf4j @Component public class AdminAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {/*** @param authenticationManager: 認證管理器* @param adminAuthenticationSuccessHandler: 認證成功處理* @param adminAuthenticationFailureHandler: 認證失敗處理*/public AdminAuthenticationProcessingFilter(CusAuthenticationManager authenticationManager, AdminAuthenticationSuccessHandler adminAuthenticationSuccessHandler, AdminAuthenticationFailureHandler adminAuthenticationFailureHandler) {super(new AntPathRequestMatcher("/login", "POST"));this.setAuthenticationManager(authenticationManager);this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);}@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (request.getContentType() == null || !request.getContentType().contains(Constants.REQUEST_HEADERS_CONTENT_TYPE)) {throw new AuthenticationServiceException("請求頭類型不支持: " + request.getContentType());}UsernamePasswordAuthenticationToken authRequest;try {MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);// 將前端傳遞的數據轉換成jsonBean數據格式User user = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest), User.class);authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), null);authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));} catch (Exception e) {throw new AuthenticationServiceException(e.getMessage());}return this.getAuthenticationManager().authenticate(authRequest);} }

    3、自定義認證管理器

    @Component public class CusAuthenticationManager implements AuthenticationManager {private final AdminAuthenticationProvider adminAuthenticationProvider;public CusAuthenticationManager(AdminAuthenticationProvider adminAuthenticationProvider) {this.adminAuthenticationProvider = adminAuthenticationProvider;}@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {Authentication result = adminAuthenticationProvider.authenticate(authentication);if (Objects.nonNull(result)) {return result;}throw new ProviderNotFoundException("Authentication failed!");} }

    4、自定義認證處理

    這里的密碼加密驗證工具類PasswordUtils可在文末源碼中查看

    @Component public class AdminAuthenticationProvider implements AuthenticationProvider {@AutowiredUserDetailsServiceImpl userDetailsService;@Autowiredprivate UserMapper userMapper;@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {// 獲取前端表單中輸入后返回的用戶名、密碼String userName = (String) authentication.getPrincipal();String password = (String) authentication.getCredentials();SecurityUser userInfo = (SecurityUser) userDetailsService.loadUserByUsername(userName);boolean isValid = PasswordUtils.isValidPassword(password, userInfo.getPassword(), userInfo.getCurrentUserInfo().getSalt());// 驗證密碼if (!isValid) {throw new BadCredentialsException("密碼錯誤!");}// 前后端分離情況下 處理邏輯...// 更新登錄令牌 - 之后訪問系統其它接口直接通過token認證用戶權限...String token = PasswordUtils.encodePassword(System.currentTimeMillis() + userInfo.getCurrentUserInfo().getSalt(), userInfo.getCurrentUserInfo().getSalt());User user = userMapper.selectById(userInfo.getCurrentUserInfo().getId());user.setToken(token);userMapper.updateById(user);userInfo.getCurrentUserInfo().setToken(token);return new UsernamePasswordAuthenticationToken(userInfo, password, userInfo.getAuthorities());}@Overridepublic boolean supports(Class<?> aClass) {return true;} }

    其中小編自定義了一個UserDetailsServiceImpl類去實現UserDetailsService類 -> 用于認證用戶詳情 和自定義一個SecurityUser類實現UserDetails類 -> 安全認證用戶詳情信息

    @Service("userDetailsService") public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;/**** 根據賬號獲取用戶信息* @param username:* @return: org.springframework.security.core.userdetails.UserDetails*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 從數據庫中取出用戶信息List<User> userList = userMapper.selectList(new EntityWrapper<User>().eq("username", username));User user;// 判斷用戶是否存在if (!CollectionUtils.isEmpty(userList)){user = userList.get(0);} else {throw new UsernameNotFoundException("用戶名不存在!");}// 返回UserDetails實現類return new SecurityUser(user);} }

    安全認證用戶詳情信息

    @Data @Slf4j public class SecurityUser implements UserDetails {/*** 當前登錄用戶*/private transient User currentUserInfo;public SecurityUser() {}public SecurityUser(User user) {if (user != null) {this.currentUserInfo = user;}}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {Collection<GrantedAuthority> authorities = new ArrayList<>();SimpleGrantedAuthority authority = new SimpleGrantedAuthority("admin");authorities.add(authority);return authorities;}@Overridepublic String getPassword() {return currentUserInfo.getPassword();}@Overridepublic String getUsername() {return currentUserInfo.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;} }

    5、自定義認證成功或失敗處理方式

  • 認證成功處理類實現AuthenticationSuccessHandler類重寫onAuthenticationSuccess方法
  • 認證失敗處理類實現AuthenticationFailureHandler類重寫onAuthenticationFailure方法
  • 在前后端分離情況下小編認證成功和失敗都返回json數據格式

    認證成功后這里小編只返回了一個token給前端,其它信息可根據個人業務實際處理

    @Component public class AdminAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse response, Authentication auth) throws IOException, ServletException {User user = new User();SecurityUser securityUser = ((SecurityUser) auth.getPrincipal());user.setToken(securityUser.getCurrentUserInfo().getToken());ResponseUtils.out(response, ApiResult.ok("登錄成功!", user));} }

    認證失敗捕捉異常自定義錯誤信息返回給前端

    @Slf4j @Component public class AdminAuthenticationFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {ApiResult result;if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {result = ApiResult.fail(e.getMessage());} else if (e instanceof LockedException) {result = ApiResult.fail("賬戶被鎖定,請聯系管理員!");} else if (e instanceof CredentialsExpiredException) {result = ApiResult.fail("證書過期,請聯系管理員!");} else if (e instanceof AccountExpiredException) {result = ApiResult.fail("賬戶過期,請聯系管理員!");} else if (e instanceof DisabledException) {result = ApiResult.fail("賬戶被禁用,請聯系管理員!");} else {log.error("登錄失敗:", e);result = ApiResult.fail("登錄失敗!");}ResponseUtils.out(response, result);} }

    溫馨小提示:

    前后端一體的情況下可通過在Spring Security核心配置類中配置異常處理接口然后通過如下方式獲取異常信息

    AuthenticationException e = (AuthenticationException) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION"); System.out.println(e.getMessage());

    三、前端頁面

    這里2個簡單的html頁面模擬前后端分離情況下登陸處理場景

    1、登陸頁

    login.html

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Login</title> </head> <body> <h1>Spring Security</h1> <form method="post" action="" onsubmit="return false"><div>用戶名:<input type="text" name="username" id="username"></div><div>密碼:<input type="password" name="password" id="password"></div><div> <!-- <label><input type="checkbox" name="remember-me" id="remember-me"/>自動登錄</label>--><button onclick="login()">登陸</button></div> </form> </body> <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js" type="text/javascript"></script> <script type="text/javascript">function login() {var username = document.getElementById("username").value;var password = document.getElementById("password").value;// var rememberMe = document.getElementById("remember-me").value;$.ajax({async: false,type: "POST",dataType: "json",url: '/login',contentType: "application/json",data: JSON.stringify({"username": username,"password": password// "remember-me": rememberMe}),success: function (result) {console.log(result)if (result.code == 200) {alert("登陸成功");window.location.href = "../home.html";} else {alert(result.message)}}});} </script> </html>

    2、首頁

    home.html

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <h3>您好,登陸成功</h3> <button onclick="window.location.href='/logout'">退出登錄</button> </body> </html>

    四、測試接口

    @Slf4j @RestController public class IndexController {@GetMapping("/")public ModelAndView showHome() {return new ModelAndView("home.html");}@GetMapping("/index")public String index() {return "Hello World ~";}@GetMapping("/login")public ModelAndView login() {return new ModelAndView("login.html");}@GetMapping("/home")public String home() {String name = SecurityContextHolder.getContext().getAuthentication().getName();log.info("登陸人:" + name);return "Hello~ " + name;}@GetMapping(value ="/admin")// 訪問路徑`/admin` 具有`crud`權限@PreAuthorize("hasPermission('/admin','crud')")public String admin() {return "Hello~ 管理員";}@GetMapping("/test") // @PreAuthorize("hasPermission('/test','t')")public String test() {return "Hello~ 測試權限訪問接口";}/*** 登錄異常處理 - 前后端一體的情況下* @param request* @param response*/@RequestMapping("/login/error")public void loginError(HttpServletRequest request, HttpServletResponse response) {AuthenticationException e = (AuthenticationException) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");log.error(e.getMessage());ResponseUtils.out(response, ApiResult.fail(e.getMessage()));} }

    五、測試訪問效果

    數據庫賬號:admin 密碼:123456

    1. 輸入錯誤用戶名提示該用戶不存在

    2. 輸入錯誤密碼提示密碼錯誤

    3. 輸入正確用戶名和賬號,提示登陸成功,然后跳轉到首頁

    登陸成功后即可正常訪問其他接口,如果是未登錄情況下將訪問不了

    溫馨小提示:這里在未登錄時或訪問未授權的接口時,后端暫時沒有做處理,相關案例將會放在后面的權限控制案例教程中講解

    六、總結

  • 在Spring Security核心配置類中設置自定義的用戶密碼校驗過濾器(AdminAuthenticationProcessingFilter)
  • 在自定義的用戶密碼校驗過濾器中配置認證管理器(CusAuthenticationManager)、認證成功處理(AdminAuthenticationSuccessHandler)和認證失敗處理(AdminAuthenticationFailureHandler)等
  • 在自定義的認證管理器中配置自定義的認證處理(AdminAuthenticationProvider)
  • 然后就是在認證處理中實現自己的相應業務邏輯等
  • Security相關代碼結構:

    本文案例源碼

    https://gitee.com/zhengqingya/java-workspace

    總結

    以上是生活随笔為你收集整理的自定义request_Spring Security 自定义登录认证(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久久国产主播 | 一二三区av | 97福利社 | 亚洲综合色站 | 999久久久 | 亚洲高清视频网站 | 成人综合站 | 全国探花| 日韩欧美在线中文字幕 | 西欧毛片 | 色婷婷综合久久 | 欧美成人精品激情在线观看 | 精品国产乱码久久久久久图片 | 久久亚洲AV无码专区成人国产 | 天天操天天干天天 | 亚洲精品一区中文字幕乱码 | 91网站在线免费观看 | 欧美丰满熟妇bbbbbb百度 | 日本三级视频在线 | 91免费看黄 | 国产精品精品 | 色男人天堂av| 日韩视频第一页 | 亚洲乱码av | 亚洲一区 欧美 | 中国妇女做爰视频 | 国产精品一区二区三区免费观看 | 91色视频在线观看 | 伊人影视久久 | 五月婷婷俺也去 | 亚洲色图50p | 国产精品操 | 精品黑人一区二区三区国语馆 | 国产ts在线播放 | 欧美破处女| 黄频在线看 | 成人亚洲天堂 | 久久午夜鲁丝片午夜精品 | 日产精品久久久久 | 国产图区| 免费三级在线 | av免费入口 | 搞黄网站在线观看 | 欧美性猛片aaaaaaa做受 | a级欧美| 黄色特级一级片 | 欧美精品黑人 | 好吊色视频一区二区三区 | 亚洲精品xxx| 自拍偷在线精品自拍偷无码专区 | 99在线成人精品视频 | 成年人的免费视频 | 欧美高h视频 | 冲田杏梨 在线 | 午夜免费片 | 欧美激情偷拍 | 欧洲黄色网 | 精品国产一区二区三区久久久 | 校花被c到呻吟求饶 | 久久国产精品久久国产精品 | 亚欧在线视频 | 激情久久久久久久 | 国产精品伦理 | 国产免费黄色小视频 | 影音先锋成人在线 | 男女野外做受全过程 | 欧美一级视频 | 翔田千里88av中文字幕 | av片在线看 | 热久久最新网址 | 意大利性荡欲xxxxxx | 91在线播放视频 | 国产大片一区二区 | 小视频在线看 | 轮番上阵免费观看在线电影 | 成人免费影片 | 亚洲大胆视频 | 60分钟| 可以看的av网址 | 亚洲综合五月 | 日韩在线二区 | 99热国产在线观看 | 国产三级午夜理伦三级 | 免费看污视频的网站 | 波多野结衣免费观看视频 | 欧美精品小视频 | 欧美日韩一区二区三区视频 | 四色在线 | 精品69 | 久夜精品 | av的天堂 | 日本三级欧美三级 | 欧美国产日韩在线视频 | a级片中文字幕 | 91蜜桃传媒精品久久久一区二区 | 亚洲国产一区二区三区a毛片 | 日韩精品第二页 | 在线观看国产小视频 | www.17c.com喷水少妇 |