亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring security(四)-spring boot

發布時間:2020-07-18 23:00:10 來源:網絡 閱讀:397 作者:艾弗森哇 欄目:開發技術

現在主流的登錄方式主要有 3 種:賬號密碼登錄、短信驗證碼登錄和第三方授權登錄,前面一節Spring security(三)---認證過程已分析了spring security賬號密碼方式登陸,現在我們來分析一下spring security短信方式認證登陸。

??Spring security 短信方式、IP驗證等類似模式登錄方式驗證,可以根據賬號密碼方式登錄步驟仿寫出來,其主要以以下步驟進行展開:

  1. 自定義Filter:

  2. 自定義Authentication

  3. 自定義AuthenticationProvider

  4. 自定義UserDetailsService

  5. SecurityConfig配置

1. 自定義filter:

??自定義filter可以根據UsernamePasswordAuthenticationFilter過濾器進行仿寫,其實質即實現AbstractAuthenticationProcessingFilter抽象類,主要流程分為:

  1. 構建構造器,并在構造器中進行配置請求路徑以及請求方式的過濾

  2. 自定義attemptAuthentication()認證步驟

  3. 在2步驟中認證過程中需要AuthenticationProvider進行最終的認證,在認證filter都需要將AuthenticationProvider設置進filter中,而管理AuthenticationProvider的是AuthenticationManager,因此我們創建過濾器filter的時候需要設置AuthenticationManager,這步具體詳情在5.1 SecurityConfig配置步驟

在第2步中attemptAuthentication()認證方法主要進行以下步驟:
?? 1).post請求認證;
?? 2).request請求獲取手機號碼和驗證碼;
?? 3).用自定義的Authentication對象封裝手機號碼和驗證碼;
?? 4).使用AuthenticationManager.authenticate()方法進行驗證。

自定義filter實現代碼:

public?class?SmsAuthenticationfilter?extends?AbstractAuthenticationProcessingFilter?{????private?boolean?postOnly?=?true;????public?SmsAuthenticationfilter()?{??????super(new?AntPathRequestMatcher(SecurityConstants.APP_MOBILE_LOGIN_URL,?"POST"));
???}


????[@Override](https://my.oschina.net/u/1162528)
????public?Authentication?attemptAuthentication(HttpServletRequest?request,?HttpServletResponse?response)?throws?AuthenticationException,?IOException,?ServletException?{????????if?(postOnly?&&?!request.getMethod().equals("POST"))?{??????????????throw?new?AuthenticationServiceException(???????????????????"Authentication?method?not?supported:?"?+?request.getMethod());
??????}
????????Assert.hasText(SecurityConstants.MOBILE_NUMBER_PARAMETER,?"mobile?parameter?must?not?be?empty?or?null");
?????
?????????String?mobile?=?request.getParameter(SecurityConstants.MOBILE_NUMBER_PARAMETER);
????????String?smsCode?=?request.ge+tParameter(SecurityConstants.MOBILE_VERIFY_CODE_PARAMETER);????????if?(mobile?==?null)?{
????????????mobile="";
????????}????????if(smsCode?==?null){
????????????smsCode="";
????????}
????????mobile?=?mobile.trim();
????????smsCode?=?smsCode.trim();
????????SmsAuthenticationToken?authRequest?=?new?SmsAuthenticationToken(mobile,smsCode);????????//?Allow?subclasses?to?set?the?"details"?property
????????setDetails(request,?authRequest);????
????????return?this.getAuthenticationManager().authenticate(authRequest);
????}protected?void?setDetails(HttpServletRequest?request,
??????????????????????????????SmsAuthenticationToken?authRequest)?{
????????authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
????}????public?void?setPostOnly(boolean?postOnly)?{????????this.postOnly?=?postOnly;
????}

}

2. Authentication:

??在filter以及后面的認證都需要使用到自定義的Authentication對象,自定義Authentication對象可以根據UsernamePasswordAuthenticationToken進行仿寫,實現AbstractAuthenticationToken抽象類。https://www.jianshu.com/p/5e19f3a9f6dd

自定義SmsAuthenticationToken:

public?class?SmsAuthenticationToken?extends?AbstractAuthenticationToken?{????private?final?Object?principal;????private?Object?credentials;????public?SmsAuthenticationToken(Object?principal,Object?credentials?)?{????????super(null);????????this.principal?=?principal;????????this.credentials=credentials;
????????setAuthenticated(false);
????}????public?SmsAuthenticationToken(Object?principal,?Object?credentials,Collection<??extends?GrantedAuthority>?authorities)?{????????super(null);????????this.principal?=?principal;????????this.credentials=credentials;
????????setAuthenticated(true);
????}

????[@Override](https://my.oschina.net/u/1162528)
????public?Object?getCredentials()?{????????return?this.credentials=credentials;
????}

????[@Override](https://my.oschina.net/u/1162528)
????public?Object?getPrincipal()?{????????return?this.principal;
????}????public?void?setAuthenticated(boolean?isAuthenticated)?throws?IllegalArgumentException?{????????if?(isAuthenticated)?{????????????throw?new?IllegalArgumentException(????????????????????"Cannot?set?this?token?to?trusted?-?use?constructor?which?takes?a?GrantedAuthority?list?instead");
????????}????????super.setAuthenticated(false);
????}

????[@Override](https://my.oschina.net/u/1162528)
????public?void?eraseCredentials()?{????????super.eraseCredentials();

????}
}

3.AuthenticationProvider

??AuthenticationProvider最終認證策略入口,短信方式驗證需自定義AuthenticationProvider。可以根據AbstractUserDetailsAuthenticationProvider進行仿寫,實現AuthenticationProvider以及MessageSourceAware接口。認證邏輯可以定義實現。焦作國醫堂胃腸醫院正規嗎:http://jz.lieju.com/zhuankeyiyuan/37174867.htm

自定義AuthenticationProvider:

public?class?SmsAuthenticationProvide?implements?AuthenticationProvider,?MessageSourceAware?{??private?UserDetailsService?userDetailsService;??private?MessageSourceAccessor?messages?=?SpringSecurityMessageSource.getAccessor();

????[@Override](https://my.oschina.net/u/1162528)
????public?void?setMessageSource(MessageSource?messageSource)?{????????this.messages?=?new?MessageSourceAccessor(messageSource);
????}????@Override
????public?Authentication?authenticate(Authentication?authentication)?{
????????Assert.isInstanceOf(SmsAuthenticationToken.class,?authentication,
????????????????messages.getMessage(????????????????????????"AbstractUserDetailsAuthenticationProvider.onlySupports",????????????????????????"Only?UsernamePasswordAuthenticationToken?is?supported"));
????????SmsAuthenticationToken?authenticationToken?=?(SmsAuthenticationToken)?authentication;????????//將驗證信息保存在SecurityContext以供UserDetailsService進行驗證
????????SecurityContext?context?=?SecurityContextHolder.getContext();
????????context.setAuthentication(authenticationToken);
????????String?mobile?=?(String)?authenticationToken.getPrincipal();????????if?(mobile?==?null)?{????????????throw?new?InternalAuthenticationServiceException("can't?obtain?user?info?");
????????}
????????mobile?=?mobile.trim();????????//進行驗證以及獲取用戶信息
????????UserDetails?user?=?userDetailsService.loadUserByUsername(mobile);????????if?(user?==?null)?{????????????throw?new?InternalAuthenticationServiceException("can't?obtain?user?info?");
????????}
????????SmsAuthenticationToken?smsAuthenticationToken?=?new?SmsAuthenticationToken(user,?user.getAuthorities());????????return?smsAuthenticationToken;
????}????@Override
????public?boolean?supports(Class<?>?authentication)?{????????return?(SmsAuthenticationToken.class.isAssignableFrom(authentication));
????}????public?void?setUserDetailsService(UserDetailsService?userDetailsService)?{????????this.userDetailsService?=?userDetailsService;
????}????public?UserDetailsService?getUserDetailsService()?{????????return?userDetailsService;
????}
}

4. UserDetailsService

??在AuthenticationProvider最終認證策略入口,認證方式實現邏輯是在UserDetailsService。可以根據自己項目自定義認證邏輯。

自定義UserDetailsService:

public?class?SmsUserDetailsService?implements?UserDetailsService?{????@Autowired
????private?RedisUtil?redisUtil;????@Override
????public?UserDetails?loadUserByUsername(String?username)?throws?UsernameNotFoundException?{????????//從SecurityContext獲取認證所需的信息(手機號碼、驗證碼)
????????SecurityContext?context?=?SecurityContextHolder.getContext();
????????SmsAuthenticationToken?authentication?=?(SmsAuthenticationToken)?context.getAuthentication();????????if(!additionalAuthenticationChecks(username,authentication)){????????????return?null;
????????}????????//獲取用戶手機號碼對應用戶的信息,包括權限等
????????return?new?User("admin",?"123456",?Arrays.asList(new?SimpleGrantedAuthority("admin")));
????}????public?boolean?additionalAuthenticationChecks(String?mobile,?SmsAuthenticationToken?smsAuthenticationToken)?{????????//獲取redis中手機鍵值對應的value驗證碼
????????String?smsCode?=?redisUtil.get(mobile).toString();????????//獲取用戶提交的驗證碼
????????String?credentials?=?(String)?smsAuthenticationToken.getCredentials();????????if(StringUtils.isEmpty(credentials)){????????????return?false;
????????}????????if?(credentials.equalsIgnoreCase(smsCode))?{????????????return?true;
????????}????????return?false;
????}
}

5.SecurityConfig

5.1 自定義Sms短信驗證組件配置SecurityConfig

??將自定義組件配置SecurityConfig中,可以根據AbstractAuthenticationFilterConfigurer(子類FormLoginConfigurer)進行仿寫SmsAuthenticationSecurityConfig,主要進行以下配置:

  1. 將默認AuthenticationManager(也可以定義的)設置到自定義的filter過濾器中

  2. 將自定義的UserDetailsService設置到自定義的AuthenticationProvide中以供使用

  3. 將過濾器添加到過濾鏈路中,實施過濾操作。(一般以加在UsernamePasswordAuthenticationFilter前)

配置SmsAuthenticationSecurityConfig:

?@Component
?public?class?SmsAuthenticationSecurityConfig?extends?SecurityConfigurerAdapter<DefaultSecurityFilterChain,?HttpSecurity>?{????@Autowired
????private?UserDetailsService?userDetailsService;????@Override
????public?void?configure(HttpSecurity?http)?throws?Exception?{????????//創建并配置好自定義SmsAuthenticationfilter,
????????SmsAuthenticationfilter?smsAuthenticationfilter?=?new?SmsAuthenticationfilter();
????????smsAuthenticationfilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
????????smsAuthenticationfilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler());
????????smsAuthenticationfilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler());????????//創建并配置好自定義SmsAuthenticationProvide
????????SmsAuthenticationProvide?smsAuthenticationProvide=new?SmsAuthenticationProvide();
????????smsAuthenticationProvide.setUserDetailsService(userDetailsService);
????????http.authenticationProvider(smsAuthenticationProvide);????????//將過濾器添加到過濾鏈路中
????????http.addFilterAfter(smsAuthenticationfilter,?UsernamePasswordAuthenticationFilter.class);
????}????@Bean
????public?CustomAuthenticationSuccessHandler?customAuthenticationSuccessHandler()?{????????return?new?CustomAuthenticationSuccessHandler();
????}????
????@Bean
????public?CustomAuthenticationFailureHandler?customAuthenticationFailureHandler()?{????????return?new?CustomAuthenticationFailureHandler();
????}
}

5.2 SecurityConfig主配置

??SecurityConfig主配置可以參照第二節Spring Security(二)--WebSecurityConfigurer配置以及filter順序進行配置。

SecurityConfig主配置:

@Configurationpublic?class?WebSecurityConfig?extends?WebSecurityConfigurerAdapter?{????@Autowired
????private?SmsAuthenticationSecurityConfig?smsAuthenticationSecurityConfig;????@Autowired
????private?CustomAuthenticationSuccessHandler?authenticationSuccessHandler;????@Autowired
????private?CustomAuthenticationFailureHandler?authenticationFailureHandler;????@Override
????protected?void?configure(HttpSecurity?http)?throws?Exception?{
????????http.headers().frameOptions().disable().and()
????????????????.formLogin()
????????????????.loginPage(SecurityConstants.APP_FORM_LOGIN_PAGE)????????????????//配置form登陸的自定義URL
????????????????.loginProcessingUrl(SecurityConstants.APP_FORM_LOGIN_URL)
????????????????.successHandler(authenticationSuccessHandler)
????????????????.failureHandler(authenticationFailureHandler)
????????????????.and()????????????????//配置smsAuthenticationSecurityConfig
????????????????.apply(smsAuthenticationSecurityConfig)
????????????????.and()????????????????//運行通過URL
????????????????.authorizeRequests()
????????????????.antMatchers(SecurityConstants.APP_MOBILE_VERIFY_CODE_URL,
?????????????????????????????SecurityConstants.APP_USER_REGISTER_URL)
????????????????.permitAll()
????????????????.and()
????????????????.csrf().disable();
????}????@Bean
????public?ObjectMapper?objectMapper(){????????return?new?ObjectMapper();
????}
}

6.其他

6.1 redis

RedisUtil工具類:

@Componentpublic?class?RedisUtil?{????@Autowired
????private?RedisTemplate<String,?Object>?redisTemplate;????/**
?????*?普通緩存獲取
?????*
?????*?@param?key?鍵
?????*?@return?值
?????*/
????public?Object?get(String?key)?{????????return?key?==?null???null?:?redisTemplate.opsForValue().get(key);
????}????/**
?????*?普通緩存放入
?????*
?????*?@param?key???鍵
?????*?@param?value?值
?????*?@return?true成功?false失敗
?????*/
????public?boolean?set(String?key,?Object?value)?{????????try?{
????????????redisTemplate.opsForValue().set(key,?value);????????????return?true;
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();????????????return?false;
????????}
????}????/**
?????*?普通緩存放入并設置時間
?????*
?????*?@param?key???鍵
?????*?@param?value?值
?????*?@param?time??時間(秒)?time要大于0?如果time小于等于0?將設置無限期
?????*?@return?true成功?false?失敗
?????*/
????public?boolean?set(String?key,?Object?value,?long?time)?{????????try?{????????????if?(time?>?0)?{
????????????????redisTemplate.opsForValue().set(key,?value,?time,?TimeUnit.SECONDS);
????????????}?else?{
????????????????set(key,?value);
????????????}????????????return?true;
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();????????????return?false;
????????}
????}
?}

redisConfig配置類:

@Configurationpublic?class?RedisConfig?{@Autowiredprivate?RedisProperties?properties;@Bean@SuppressWarnings("all")@ConditionalOnClass(RedisConnectionFactory.class)public?RedisTemplate<String,?Object>?redisTemplate(RedisConnectionFactory?factory)?{
????????RedisTemplate<String,?Object>?template?=?new?RedisTemplate<String,?Object>();
????????template.setConnectionFactory(factory);
????????Jackson2JsonRedisSerializer?jackson2JsonRedisSerializer?=?new?Jackson2JsonRedisSerializer(Object.class);
????????ObjectMapper?om?=?new?ObjectMapper();
????????om.setVisibility(PropertyAccessor.ALL,?JsonAutoDetect.Visibility.ANY);
????????om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
????????jackson2JsonRedisSerializer.setObjectMapper(om);
????????StringRedisSerializer?stringRedisSerializer?=?new?StringRedisSerializer();????????//?key采用String的序列化方式
????????template.setKeySerializer(stringRedisSerializer);????????//?hash的key也采用String的序列化方式
????????template.setHashKeySerializer(stringRedisSerializer);????????//?value序列化方式采用jackson
????????template.setValueSerializer(jackson2JsonRedisSerializer);????????//?hash的value序列化方式采用jackson
????????template.setHashValueSerializer(jackson2JsonRedisSerializer);
????????template.afterPropertiesSet();????????return?template;
????}????@Bean
????@Qualifier("redisConnectionFactory")????public?RedisConnectionFactory?redisConnectionFactory(){
????????RedisStandaloneConfiguration?redisConfig?=?new?RedisStandaloneConfiguration();
????????redisConfig.setHostName(properties.getHost());
????????redisConfig.setPort(properties.getPort());
????????redisConfig.setPassword(RedisPassword.of(properties.getPassword()));
????????redisConfig.setDatabase(properties.getDatabase());????????//redis連接池數據設置
????????JedisClientConfiguration.JedisClientConfigurationBuilder?builder?=?JedisClientConfiguration.builder();????????if?(this.properties.getTimeout()?!=?null)?{
????????????Duration?timeout?=?this.properties.getTimeout();
????????????builder.readTimeout(timeout).connectTimeout(timeout);
????????}
????????RedisProperties.Pool?pool?=?this.properties.getJedis().getPool();????????if?(pool?!=?null)?{
????????????builder.usePooling().poolConfig(this.jedisPoolConfig(pool));
????????}
????????JedisClientConfiguration?jedisClientConfiguration?=?builder.build();????????//根據兩個配置類生成JedisConnectionFactory
????????return?new?JedisConnectionFactory(redisConfig,jedisClientConfiguration);

????}????private?JedisPoolConfig?jedisPoolConfig(RedisProperties.Pool?pool)?{
????????JedisPoolConfig?config?=?new?JedisPoolConfig();
????????config.setMaxTotal(pool.getMaxActive());
????????config.setMaxIdle(pool.getMaxIdle());
????????config.setMinIdle(pool.getMinIdle());????????if?(pool.getMaxWait()?!=?null)?{
????????????config.setMaxWaitMillis(pool.getMaxWait().toMillis());
????????}????????return?config;
????}
}

7.總結

??可以根據短信驗證登陸模式去實現類似的驗證方式,可以結合本節的例子進行跟項目結合起來,減少開發時間。后續還有第三方登陸方式分析以案例。最后錯誤請評論指出!


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

延川县| 永仁县| 腾冲县| 尤溪县| 曲松县| 博罗县| 榆林市| 横峰县| 长乐市| 宣武区| 越西县| 平顶山市| 宁安市| 庆阳市| 巨野县| 梨树县| 玛多县| 准格尔旗| 鹤山市| 合作市| 忻州市| 铜鼓县| 岑巩县| 楚雄市| 灵武市| 黄陵县| 察雅县| 湖南省| 新化县| 宣恩县| 商水县| 滨州市| 莱芜市| 敖汉旗| 新河县| 西和县| 九江县| 民丰县| 登封市| 甘洛县| 孙吴县|