国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > Java > 正文

spring security自定義認證登錄的全過程記錄

2024-07-13 10:15:14
字體:
來源:轉載
供稿:網友

spring security使用分類:

如何使用spring security,相信百度過的都知道,總共有四種用法,從簡到深為:

1、不用數據庫,全部數據寫在配置文件,這個也是官方文檔里面的demo;

2、使用數據庫,根據spring security默認實現代碼設計數據庫,也就是說數據庫已經固定了,這種方法不靈活,而且那個數據庫設計得很簡陋,實用性差;

3、spring security和Acegi不同,它不能修改默認filter了,但支持插入filter,所以根據這個,我們可以插入自己的filter來靈活使用;

4、暴力手段,修改源碼,前面說的修改默認filter只是修改配置文件以替換filter而已,這種是直接改了里面的源碼,但是這種不符合OO設計原則,而且不實際,不可用。

本文主要介紹了關于spring security自定義認證登錄的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

1.概要

1.1.簡介

spring security是一種基于 Spring AOP 和 Servlet 過濾器的安全框架,以此來管理權限認證等。

1.2.spring security 自定義認證流程

1)認證過程

生成未認證的AuthenticationToken                 

 ↑(獲取信息)  (根據AuthenticationToken分配provider)      AuthenticationFilter -> AuthenticationManager -> AuthenticationProvider        ↓(認證)       UserDetails(一般查詢數據庫獲取)        ↓(通過)        生成認證成功的AuthenticationToken         ↓(存放)        SecurityContextHolder

2)將AuthenticationFilter加入到security過濾鏈(資源服務器中配置),如:

http.addFilterBefore(AuthenticationFilter, AbstractPreAuthenticatedProcessingFilter.class)

或者:

http.addFilterAfter(AuthenticationFilter, UsernamePasswordAuthenticationFilter.class)

2.以手機號短信登錄為例

2.1.開發環境

  • SpringBoot
  • Spring security
  • Redis

2.2.核心代碼分析

2.2.1.自定義登錄認證流程

2.2.1.1.自定義認證登錄Token

/** * 手機登錄Token * * @author : CatalpaFlat */public class MobileLoginAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationToken.class.getName()); private final Object principal; public MobileLoginAuthenticationToken(String mobile) { super(null); this.principal = mobile; this.setAuthenticated(false); logger.info("MobileLoginAuthenticationToken setAuthenticated ->false loading ..."); } public MobileLoginAuthenticationToken(Object principal,      Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; // must use super, as we override super.setAuthenticated(true); logger.info("MobileLoginAuthenticationToken setAuthenticated ->true loading ..."); } @Override public void setAuthenticated(boolean authenticated) { if (authenticated) {  throw new IllegalArgumentException(   "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return this.principal; } @Override public void eraseCredentials() { super.eraseCredentials(); }}

注:

setAuthenticated():判斷是否已認證

  • 在過濾器時,會生成一個未認證的AuthenticationToken,此時調用的是自定義token的setAuthenticated(),此時設置為false -> 未認證
  • 在提供者時,會生成一個已認證的AuthenticationToken,此時調用的是父類的setAuthenticated(),此時設置為true -> 已認證

2.2.1.1.自定義認證登錄過濾器

/** * 手機短信登錄過濾器 * * @author : CatalpaFlat */public class MobileLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private boolean postOnly = true; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationFilter.class.getName()); @Getter @Setter private String mobileParameterName; public MobileLoginAuthenticationFilter(String mobileLoginUrl, String mobileParameterName,      String httpMethod) { super(new AntPathRequestMatcher(mobileLoginUrl, httpMethod)); this.mobileParameterName = mobileParameterName; logger.info("MobileLoginAuthenticationFilter loading ..."); } @Override public Authentication attemptAuthentication(HttpServletRequest request,      HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {  throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } //get mobile String mobile = obtainMobile(request); //assemble token MobileLoginAuthenticationToken authRequest = new MobileLoginAuthenticationToken(mobile); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /** * 設置身份認證的詳情信息 */ private void setDetails(HttpServletRequest request, MobileLoginAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } /** * 獲取手機號 */ private String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameterName); } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; }}

注:attemptAuthentication()方法:

  • 過濾指定的url、httpMethod
  • 獲取所需請求參數數據封裝生成一個未認證的AuthenticationToken
  • 傳遞給AuthenticationManager認證

2.2.1.1.自定義認證登錄提供者

/** * 手機短信登錄認證提供者 * * @author : CatalpaFlat */public class MobileLoginAuthenticationProvider implements AuthenticationProvider { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationProvider.class.getName()); @Getter @Setter private UserDetailsService customUserDetailsService; public MobileLoginAuthenticationProvider() { logger.info("MobileLoginAuthenticationProvider loading ..."); } /** * 認證 */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { //獲取過濾器封裝的token信息 MobileLoginAuthenticationToken authenticationToken = (MobileLoginAuthenticationToken) authentication; //獲取用戶信息(數據庫認證) UserDetails userDetails = customUserDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); //不通過 if (userDetails == null) {  throw new InternalAuthenticationServiceException("Unable to obtain user information"); } //通過 MobileLoginAuthenticationToken authenticationResult = new MobileLoginAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } /** * 根據token類型,來判斷使用哪個Provider */ @Override public boolean supports(Class<?> authentication) { return MobileLoginAuthenticationToken.class.isAssignableFrom(authentication); }}

注:authenticate()方法

  • 獲取過濾器封裝的token信息
  • 調取UserDetailsService獲取用戶信息(數據庫認證)->判斷通過與否
  • 通過則封裝一個新的AuthenticationToken,并返回

2.2.1.1.自定義認證登錄認證配置

@Configuration(SpringBeanNameConstant.DEFAULT_CUSTOM_MOBILE_LOGIN_AUTHENTICATION_SECURITY_CONFIG_BN)public class MobileLoginAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationSecurityConfig.class.getName()); @Value("${login.mobile.url}") private String defaultMobileLoginUrl; @Value("${login.mobile.parameter}") private String defaultMobileLoginParameter; @Value("${login.mobile.httpMethod}") private String defaultMobileLoginHttpMethod; @Autowired private CustomYmlConfig customYmlConfig; @Autowired private UserDetailsService customUserDetailsService; @Autowired private AuthenticationSuccessHandler customAuthenticationSuccessHandler; @Autowired private AuthenticationFailureHandler customAuthenticationFailureHandler; public MobileLoginAuthenticationSecurityConfig() { logger.info("MobileLoginAuthenticationSecurityConfig loading ..."); } @Override public void configure(HttpSecurity http) throws Exception { MobilePOJO mobile = customYmlConfig.getLogins().getMobile(); String url = mobile.getUrl(); String parameter = mobile.getParameter().getMobile(); String httpMethod = mobile.getHttpMethod(); MobileLoginAuthenticationFilter mobileLoginAuthenticationFilter = new MobileLoginAuthenticationFilter(StringUtils.isBlank(url) ? defaultMobileLoginUrl : url,  StringUtils.isBlank(parameter) ? defaultMobileLoginUrl : parameter, StringUtils.isBlank(httpMethod) ? defaultMobileLoginHttpMethod : httpMethod); mobileLoginAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); mobileLoginAuthenticationFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler); mobileLoginAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler); MobileLoginAuthenticationProvider mobileLoginAuthenticationProvider = new MobileLoginAuthenticationProvider(); mobileLoginAuthenticationProvider.setCustomUserDetailsService(customUserDetailsService); http.authenticationProvider(mobileLoginAuthenticationProvider)  .addFilterAfter(mobileLoginAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); }}

注:configure()方法

實例化AuthenticationFilter和AuthenticationProvider

將AuthenticationFilter和AuthenticationProvider添加到spring security中。

2.2.2.基于redis自定義驗證碼校驗

2.2.2.1.基于redis自定義驗證碼過濾器

/** * 驗證碼過濾器 * * @author : CatalpaFlat */@Component(SpringBeanNameConstant.DEFAULT_VALIDATE_CODE_FILTER_BN)public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(ValidateCodeFilter.class.getName()); @Autowired private CustomYmlConfig customYmlConfig; @Autowired private RedisTemplate<Object, Object> redisTemplate; /**  * 驗證請求url與配置的url是否匹配的工具類  */ private AntPathMatcher pathMatcher = new AntPathMatcher(); public ValidateCodeFilter() {  logger.info("Loading ValidateCodeFilter..."); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,         FilterChain filterChain) throws ServletException, IOException {  String url = customYmlConfig.getLogins().getMobile().getUrl();  if (pathMatcher.match(url, request.getRequestURI())) {   String deviceId = request.getHeader("deviceId");   if (StringUtils.isBlank(deviceId)) {    throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Not deviceId in the head of the request");   }   String codeParamName = customYmlConfig.getLogins().getMobile().getParameter().getCode();   String code = request.getParameter(codeParamName);   if (StringUtils.isBlank(code)) {    throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Not code in the parameters of the request");   }   String key = SystemConstant.DEFAULT_MOBILE_KEY_PIX + deviceId;   SmsCodePO smsCodePo = (SmsCodePO) redisTemplate.opsForValue().get(key);   if (smsCodePo.isExpried()){    throw new CustomException(HttpStatus.BAD_REQUEST.value(), "The verification code has expired");   }   String smsCode = smsCodePo.getCode();   if (StringUtils.isBlank(smsCode)) {    throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Verification code does not exist");   }   if (StringUtils.equals(code, smsCode)) {    redisTemplate.delete(key);    //let it go    filterChain.doFilter(request, response);   } else {    throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Validation code is incorrect");   }  }else {   //let it go   filterChain.doFilter(request, response);  } }}

注:doFilterInternal()

自定義驗證碼過濾校驗

2.2.2.2.將自定義驗證碼過濾器添加到spring security過濾器鏈

http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class)

注:添加到認證預處理過濾器前

3.測試效果

spring,security,認證,登錄

spring,security,認證,登錄

spring,security,認證,登錄

spring,security,認證,登錄

最后附上源碼地址:https://gitee.com/CatalpaFlat/springSecurity.git  

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 屏南县| 双峰县| 临桂县| 海南省| 象山县| 云安县| 乌兰县| 沙雅县| 晋城| 米泉市| 扎兰屯市| 互助| 佛冈县| 永清县| 合山市| 怀安县| 云安县| 望谟县| 本溪市| 荥阳市| 安宁市| 阿克苏市| 灵丘县| 昆明市| 石阡县| 合水县| 佛学| 丰台区| 东丰县| 丰城市| 六安市| 铁岭县| 红河县| 东源县| 定南县| 汉寿县| 开鲁县| 湖南省| 嘉义市| 扎鲁特旗| 南城县|