重构短信验证


//@EnableWebSecurity
@Component
public class SecurityConfig extends AbstractChannelSecurityConfig {
    @Autowired
    private SecurityProperties securityProperties;
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;
//    @Bean
//    public PasswordEncoder passwordEncoder(){
//        return new BCryptPasswordEncoder();
//    }
    @Autowired
    private ValidateCodeSecurityConfig validateCodeSecurityConfig;
    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        applyPasswordAuthenticationConfig(http);
        http
                .apply(validateCodeSecurityConfig)
                .and()
                .apply(smsCodeAuthenticationSecurityConfig)
                .and()
                .rememberMe()
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
                    .userDetailsService(userDetailsService)
                .and()
                .authorizeRequests()
                .antMatchers( "/login",
                        "/myLogin",
                        "/loginMobile",
                        "/css/**", "/images/**", "/js/**","/fonts/**",
                        "/h2/**","/h2-console/**","/code/*"
                )
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable()
                .and()
                .csrf().disable();
    }

    // 内存级别用户
//    @Override
//    @Bean
//    public UserDetailsService userDetailsService(){
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        manager.createUser(User.withUsername("user").password(new BCryptPasswordEncoder().encode("lh123")).roles("USER").build());
//        manager.createUser(User.withUsername("fly").password(new BCryptPasswordEncoder().encode("lh123")).roles("ADMIN").build());
//        return manager;
//    }

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

//    @Bean
//    public AuthenticationProvider authenticationProvider() {
//        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
//        authenticationProvider.setUserDetailsService(userDetailsService);
//        authenticationProvider.setPasswordEncoder(passwordEncoder);
//        return authenticationProvider;
//    }

    /**
     * 认证信息管理
     */
//    @Autowired
//    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(userDetailsService);
//        auth.authenticationProvider(authenticationProvider());
//    }

    @Autowired
    private DataSource dataSource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
		tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }
}


public class AbstractChannelSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    protected AuthenticationSuccessHandler imoocAuthenticationSuccessHandler;

    @Autowired
    protected AuthenticationFailureHandler imoocAuthenticationFailureHandler;

    protected void applyPasswordAuthenticationConfig(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/myLogin")
                .loginProcessingUrl("/login")
                .successHandler(imoocAuthenticationSuccessHandler)
                .failureHandler(imoocAuthenticationFailureHandler);
    }

}
/**
 * 将随机验证码过滤器配置到 spring security 过滤器认证最前端
 */
@Component
public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
    @Autowired
    private Filter validateCodeFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class);
    }
}

/**
 * 保存的密码是加密或未加密都可以,兼容老系统
 */
@Component("passwordEncoder")
public class MyPasswordEncoder extends BCryptPasswordEncoder {
    private Pattern BCRYPT_PATTERN = Pattern
            .compile("\A\$2(a|y|b)?\$(\d\d)\$[./0-9A-Za-z]{53}");

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        // 数据库密码没加密
        if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
            System.out.println("rawPassword = " + rawPassword);
            System.out.println("encodedPassword = " + encodedPassword);
            // TODO 如果密码正确更新为加密的密码
            return rawPassword.equals(encodedPassword);
        }

        return super.matches(rawPassword, encodedPassword);
    }
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>登录</title>
    <link rel="stylesheet" th:href="@{/css/element-ui2.13.2/index.css}" type="text/css">
    <script th:src="@{/js/vue.min.js}"></script>
    <script th:src="@{/js/vue-router.min.js}"></script>
    <script th:src="@{/js/element-ui2.13.2/index.js}"></script>
    <script th:src="@{/js/axios.min.js}"></script>
    <script th:src="@{/js/jquery.min.js}"></script>
</head>
<body>
<div id="login">
    <el-form :model="ruleForm" size="medium" ref="ruleFormRef" label-width="100px">
        <el-form-item label="username">
            <el-input v-model="ruleForm.username"></el-input>
        </el-form-item>
        <el-form-item label="password">
            <!--show-password-->
            <el-input v-model="ruleForm.password"></el-input>
        </el-form-item>
        <el-form-item label="imageCode">
            <el-row>
                <el-col :span="8">
                    <el-input v-model="ruleForm.imageCode"></el-input>
                </el-col>
                <el-col :span="4">
                    <div @click="getCaptcha">
                        <img style=" 100px; height: 50px" alt="验证码" title="点击获取验证码"
                             :src="captchaUri"/>
                    </div>
                </el-col>
            </el-row>
        </el-form-item>
        <el-form-item label="rememberMe">
            <el-checkbox label="记住我" v-model="ruleForm.rememberMe"></el-checkbox>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="submitForm('ruleFormRef')">submit</el-button>
            <el-button @click="resetForm('ruleFormRef')">reset</el-button>
        </el-form-item>
    </el-form>
    <h2>短信登录</h2>
    <el-form :model="smsForm" size="medium" ref="smsFormRef" label-width="100px">
        <el-form-item label="username">
            <el-input v-model="smsForm.mobile"></el-input>
        </el-form-item>
        <el-form-item label="smsCode">
            <el-row>
                <el-col :span="8">
                    <el-input v-model="smsForm.smsCode"></el-input>
                </el-col>
                <el-col :span="4">
                    <div>
                        <button @click="sendSmsCaptcha">发送验证码</button>
                    </div>
                </el-col>
            </el-row>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="submitSmsForm('smsFormRef')">submit</el-button>
            <el-button @click="resetForm('smsFormRef')">reset</el-button>
        </el-form-item>
    </el-form>
</div>
<script>
    var vue = new Vue({
        el: "#login",
        data: {
            ruleForm: {
                username: '',
                password: '',
                imageCode: '',
                rememberMe:false
            },
            smsForm:{
                mobile:'17811111112',
                smsCode:''
            },
            rules: {
                username: [
                    {required: true, message: 'please input username', trigger: 'blur'},
                ],
                imageCode: [
                    {required: true, message: 'please input imageCode', trigger: 'blur'},
                ],
                mobile:[
                    {required: true, message: 'please input mobile', trigger: 'blur'},
                ],
                smsCode:[
                    {required: true, message: 'please input smsCode', trigger: 'blur'},
                ]
            },
            captchaUri: '/code/image?width=100&height=50'
        },
        methods: {
            getCaptcha: function () {
                //点击获取验证码
                this.captchaUri = this.captchaUri + Math.random()
            },
            sendSmsCaptcha:function(){
                if (this.smsForm.mobile==''){
                    this.$message.warn("请输入手机号");
                    return
                }
                $.ajax({
                    type: 'GET',
                    data: {
                        'mobile': this.smsForm.mobile
                    },
                    url: '/code/sms',
                    dataType: 'json'
                });
            },
            submitSmsForm:function(formName){
                var that = this;
                $.ajax({
                    type: 'POST',
                    data: {
                        'mobile': this.smsForm.mobile,
                        'smsCode': this.smsForm.smsCode,
                    },
                    url: '/loginMobile',
                    dataType: 'json',
                    success: function (res) {
                        if (res.error_code == '0') {
                            window.location.href = "http://localhost:9090/home"
                        } else {
                            this.$message.error(res.message || "登录失败");
                        }
                    },
                    error: function (res) {
                        that.$message.error(res.responseJSON.message || "登录失败");
                    }
                });
            },
            submitForm: function (formName) {
                var that = this;
                $.ajax({
                    type: 'POST',
                    data: {
                        'username': this.ruleForm.username,
                        'password': this.ruleForm.password,
                        'imageCode': this.ruleForm.imageCode,
                        'remember-me': this.ruleForm.rememberMe
                    },
                    url: '/login',
                    dataType: 'json',
                    success: function (res) {
                        if (res.error_code == '0') {
                            window.location.href = "http://localhost:9090/home"
                        } else {
                            this.$message.error(res.message || "用户名或密码错误");
                        }
                    },
                    error: function (res) {
                        that.$message.error(res.responseJSON.message || "用户名或密码错误");
                    }
                });
                // axios.post('/login',{
                //     username:this.username,
                //     password:this.password
                // }).then(function (res) {
                //     if (res.error_code=='0'){
                //         window.location.href="http://localhost:9090/home"
                //     }
                // }).catch(function (err) {
                //     console.log(err)
                // });

            },
            resetForm: function (formName) {
                this.$refs[formName].resetFields();
            }
        }
    })
</script>
</body>
</html>
原文地址:https://www.cnblogs.com/fly-book/p/13259151.html