欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringSecurity 手機(jī)號(hào)登錄功能實(shí)現(xiàn)

 更新時(shí)間:2023年12月15日 09:56:44   作者:JunSouth  
這篇文章主要介紹了SpringSecurity 手機(jī)號(hào)登錄功能實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧

一、工作流程 

1.向手機(jī)發(fā)送驗(yàn)證碼,第三方短信發(fā)送平臺(tái),如阿里云短信。
2.手機(jī)獲取驗(yàn)證碼后,在表單中輸入驗(yàn)證碼。
3.使用自定義過(guò)濾器?SmsCodeValidateFilter?。
4.短信校驗(yàn)通過(guò)后,使用自定義手機(jī)認(rèn)證過(guò)濾器?SmsCodeAuthenticationFilter校驗(yàn)手機(jī)號(hào)碼是否存在?。
5.自定義?SmsCodeAuthenticationToken?提供給?SmsCodeAuthenticationFilter?。
6.自定義?SmsCodeAuthenticationProvider?提供給?AuthenticationManager?。
7.創(chuàng)建針對(duì)手機(jī)號(hào)查詢(xún)用戶(hù)信息的?SmsCodeUserDetailsService?,提交給?。SmsCodeAuthenticationProvider?。
8.自定義?SmsCodeSecurityConfig?配置類(lèi)將上面組件連接起來(lái)。
9.將?SmsCodeSecurityConfig?添加到?LearnSrpingSecurity?安全配置的過(guò)濾器鏈上。

二、實(shí)現(xiàn) 

2.1、驗(yàn)證碼生成、發(fā)送

/**
 * 創(chuàng)建驗(yàn)證碼生成器
 */
@Component
public class SmsCodeGenerator {
    public String generate() {
        return RandomStringUtils.randomNumeric(4);
    }
}
/**
 * 驗(yàn)證碼發(fā)送器
 */
@Component
public class SmsCodeSender {
    public void send(String mobile, String code) {
        System.out.println("向手機(jī)" + mobile + "發(fā)送短信驗(yàn)證碼" + code);
    }
}
/**
 * 發(fā)送短信接口
 */
@RestController
public class ValidateCodeController {
    @Autowired
    private SmsCodeGenerator smsCodeGenerator;
    @Resource
    private SmsCodeSender smsCodeSender;
    @Resource
    private RedisTemplate redisTemplate;
    @GetMapping("/code/sms")
    public String createSmsCode(@RequestParam String mobile) throws IOException {
        //獲取驗(yàn)證碼
        String smsCode = smsCodeGenerator.generate();
        //把驗(yàn)證碼設(shè)置到redis
        redisTemplate.boundValueOps(SecurityConstants.getValidCodeKey(mobile)).set(smsCode, 300, TimeUnit.SECONDS);
        smsCodeSender.send("18360903475", "登錄驗(yàn)證碼為:" + smsCode + ",五分鐘過(guò)期");
        return "驗(yàn)證碼是 : " + smsCode;
    }
}

2.2、手機(jī)號(hào)碼認(rèn)證 Token

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import java.util.Collection;
/**
 * 手機(jī)號(hào)碼認(rèn)證 Token
 */
public class PhoneNumAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
    /**
     * principal的作用有兩個(gè), 在未登錄之前是用戶(hù)名,那么在登錄之后是用戶(hù)的信息。
     */
    private final Object principal;
    /**
     * 構(gòu)造
     * @param principal 手機(jī)號(hào)碼
     */
    public PhoneNumAuthenticationToken(Object principal) {
        super(null);
        this.principal = principal;
        // 用于指示AbstractSecurityInterceptor是否應(yīng)向AuthenticationManager提供身份驗(yàn)證令牌
        setAuthenticated(false);
    }
    /**
     * 構(gòu)造
     * @param principal 用戶(hù)信息
     * @param authorities 用戶(hù)權(quán)限列表
     */
    public PhoneNumAuthenticationToken(Object principal,Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        // 用于指示AbstractSecurityInterceptor是否應(yīng)向AuthenticationManager提供身份驗(yàn)證令牌
        setAuthenticated(true);
    }
    /**
     * 正常這個(gè)是返回密碼,但手機(jī)登錄沒(méi)有密碼,不用管
     */
    @Override
    public Object getCredentials() {
        return null;
    }
    /**
     * 獲取手機(jī)號(hào)或用戶(hù)信息
     */
    @Override
    public Object getPrincipal() {
        return this.principal;
    }
}

2.3、攔截請(qǐng)求、獲取手機(jī)號(hào)碼 

/**
 * 手機(jī)號(hào)碼攔截器, 獲取手機(jī)號(hào)碼
 */
public class PhoneNumAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    public PhoneNumAuthenticationFilter() {
        super(new AntPathRequestMatcher("/phoneLogin", "POST"));
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!Objects.equals(request.getMethod(),"POST")) {
            throw new AuthenticationServiceException("身份驗(yàn)證方法需為:'POST'請(qǐng)求");
        }
        // 獲取手機(jī)號(hào)
        String phoneNum = Optional.ofNullable(request.getParameter(Constants.PHONE_NUM_PARAMETER)).map(String::trim).orElse("");
        // new 手機(jī)號(hào)碼驗(yàn)證Token
        PhoneNumAuthenticationToken authRequest = new PhoneNumAuthenticationToken(phoneNum);
        // 身份驗(yàn)證詳細(xì)信息
        authRequest.setDetails(super.authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

2.4、短信驗(yàn)證碼驗(yàn)證過(guò)濾器

/**
 * 短信驗(yàn)證碼驗(yàn)證過(guò)濾器
 */
@Component
public class SmsCodeFilter extends OncePerRequestFilter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private CustomizeAuthencationFailureHandler customizeAuthencationFailureHandler;
    @Override
    protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {
        /**
         * uri = /phoneLogin 即手機(jī)號(hào)碼登錄才攔截
         */
        if (Objects.equals(Constants.SMS_LOGIN_URI,request.getRequestURI())) {
            try{
                // 驗(yàn)證手機(jī)驗(yàn)證碼
                validateProcess(request);
            }catch (AuthenticationException ex) {
                customizeAuthencationFailureHandler.onAuthenticationFailure(request, response, ex);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
    /**
     * 驗(yàn)證手機(jī)驗(yàn)證碼
     */
    private void validateProcess(HttpServletRequest request){
        // 獲取手機(jī)號(hào)
        String msgCode = stringRedisTemplate.opsForValue().get(Constants.SMS_CODE_SESSION_KEY);
        String code = request.getParameter(Constants.MSG_CODE);
        if(Strings.isBlank(code)) {
            throw new InternalAuthenticationServiceException("短信驗(yàn)證碼不能為空.");
        }
        if(null == msgCode) {
            throw new InternalAuthenticationServiceException("短信驗(yàn)證碼已失效.");
        }
        if(!code.equals(msgCode)) {
            throw new InternalAuthenticationServiceException("短信驗(yàn)證碼錯(cuò)誤.");
        }
    }
}

2.5、繼承 WebSecurityConfigurerAdapter 配置 HttpSecurity 

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 數(shù)據(jù)源
     */
    @Resource
    private DataSource dataSource;
    /**
     * 用戶(hù)信息服務(wù)
     */
    @Resource
    private UserAuthentication userAuthentication;
    /**
     * 成功處理
     */
    @Resource
    private CustomizeAuthencationSuccessHandler customizeAuthencationSuccessHandler;
    /**
     * 失敗處理
     */
    @Resource
    private CustomizeAuthencationFailureHandler customizeAuthencationFailureHandler;
    /**
     * 用戶(hù)登出處理
     */
    @Resource
    private UserLogoutSuccessHandler userLogoutSuccessHandler;
    /**
     * 多用戶(hù)登錄處理
     */
    @Resource
    private MutilpleSessionHandler mutilpleSessionHandler;
    /**
     * 密碼編碼器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    /**
     * 手機(jī)號(hào)碼登錄驗(yàn)證處理
     */
    @Resource
    private DaoPhoneNumAuthenticationProvider daoPhoneNumAuthenticationProvider;
    /**
     * 信息驗(yàn)證碼過(guò)濾器
     */
    @Resource
    private SmsCodeFilter smsCodeFilter;
    /**
     * 把AuthenticationManager公開(kāi)
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    /**
     * 配置自定義驗(yàn)證查詢(xún)/加密工具
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userAuthentication).passwordEncoder(passwordEncoder());
    }
    /**
     * 手機(jī)號(hào)碼登錄攔截器
     */
    @Bean
    public PhoneNumAuthenticationFilter phoneNumAuthenticationFilter() throws Exception {
        // 手機(jī)號(hào)碼攔截器, 獲取手機(jī)號(hào)碼
        PhoneNumAuthenticationFilter phoneNumAuthenticationFilter = new PhoneNumAuthenticationFilter();
        phoneNumAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
        //使用手機(jī)號(hào)登錄失敗了如何處理
        phoneNumAuthenticationFilter.setAuthenticationFailureHandler(customizeAuthencationFailureHandler);
        // 使用手機(jī)號(hào)登錄成功了如何處理
        phoneNumAuthenticationFilter.setAuthenticationSuccessHandler(customizeAuthencationSuccessHandler);
        return phoneNumAuthenticationFilter;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // 加入短信驗(yàn)證碼過(guò)濾器
            .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
            // 加入手機(jī)號(hào)碼登錄過(guò)濾器
            .addFilterAfter(phoneNumAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            // 加入手機(jī)號(hào)碼登錄驗(yàn)證提供者
            .authenticationProvider(daoPhoneNumAuthenticationProvider)
            // 表單登錄
            .formLogin()
            // 未登錄跳轉(zhuǎn)登錄頁(yè)面
            .loginPage("/login.html")
            // 指定登錄路徑
            .loginProcessingUrl("/login")
            // 用戶(hù)登錄成功的處理
            .successHandler(customizeAuthencationSuccessHandler)
            // 用戶(hù)登錄失敗的處理
            .failureHandler(customizeAuthencationFailureHandler)
            // 因?yàn)橛脩?hù)傳入過(guò)來(lái)的token, 需要再次進(jìn)行校驗(yàn)
            .userDetailsService(userAuthentication)
            .tokenValiditySeconds(3600)
			// .alwaysRemember(true)
            // 認(rèn)證配置
            .and()
            .authorizeRequests()
            //不攔截的Url
            .antMatchers("/login.html", "/image/code", "/smsCode", "/css/**", "/js/**", "/phoneLogin").permitAll()
            .anyRequest()  //所有的請(qǐng)求
            .authenticated()   //認(rèn)證之后就可以訪問(wèn)
            // 多端登錄限制,限制一個(gè)賬號(hào)同時(shí)只能一個(gè)人登錄
            .and()
            .sessionManagement()
            .maximumSessions(1)
            .expiredSessionStrategy(mutilpleSessionHandler)
            .and()
            // 登出配置
            .and()
            .logout()
            .logoutUrl("/logout")
            // 登出成功處理
            .logoutSuccessHandler(userLogoutSuccessHandler)
            .and()
            .csrf().disable();
    }
}

到此這篇關(guān)于SpringSecurity 手機(jī)號(hào)登錄的文章就介紹到這了,更多相關(guān)SpringSecurity 手機(jī)號(hào)登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論