springboot +spring security4 自定义手机号码+短信验证码登录

spring security 默认登录方式都是用户名+密码登录,项目中使用手机+ 短信验证码登录, 没办法,只能实现修改:

需要修改的地方:

1 、自定义 AuthenticationProvider 配置:

package com.ycmedia.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.ycmedia.constants.Constants;
import com.ycmedia.entity.Customer;
import com.ycmedia.entity.Role;
import com.ycmedia.service.UserService;
import com.ycmedia.utils.HttpRequest;

/**
 * @author 自定义验证
 *
 */
@Component
public class YcAnthencationProder implements AuthenticationProvider {
    @Autowired
    private UserService userService;
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    @Autowired
    private Environment env;

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
//        CustomWebAuthenticationDetails details = (CustomWebAuthenticationDetails) authentication
//                .getDetails(); // 如上面的介绍,这里通过authentication.getDetails()获取详细信息
        // 用户名
        String username = authentication.getName();
        // 验证码
        String password = (String) authentication.getCredentials();
        Customer user = userService.getUserByname(username);
        List<SimpleGrantedAuthority> auths = new ArrayList<>();
        //游客=》提示用户去注册
        if(user==null){
            //授权
            auths.add(new SimpleGrantedAuthority(Role.ROLE_TOURIST.toString()));
            auths.add(new SimpleGrantedAuthority(username));
            auths.add(new SimpleGrantedAuthority(password));
            return new UsernamePasswordAuthenticationToken(new Customer(), password,
                    auths);
        }else{
            //存在此用户,调用登录接口
            String data = HttpRequest.sendGet(env.getProperty("login.url"),
                    "mobile=" + username+"&smsCode="+password);
            JSONObject json = JSONObject.parseObject(data);
            if(json.getBoolean("success")==true){
                //验证码和手机号码正确,返回用户权限
                switch(user.getRole()){
                  case 0:auths.add(new SimpleGrantedAuthority(Role.ROLE_USER.toString()));
                  case 1:auths.add(new SimpleGrantedAuthority(Role.ROLE_CHANNEL.toString()));
                  case 2:auths.add(new SimpleGrantedAuthority(Role.ROLE_ADMIN.toString()));
                }
            }else{
                //验证消息放到权限里面, 页面提示
                auths.add(new SimpleGrantedAuthority(Role.ROLE_WRONGCODE.toString()));
                auths.add(new SimpleGrantedAuthority(username));
                auths.add(new SimpleGrantedAuthority(password));
            }
        }
        return new UsernamePasswordAuthenticationToken(user, password,
                auths);

    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

==================这里把验证码当成password

security  安全中添加:

 

之前一直跑不通, 是因为在config 中引入我自己的 provider, 结果代码跳不进去, 最后用spring 默认的provier  放进去,才可以。到现在还不明白

============================================================================

因为springsecurity 授权 顺序是 1 :调用AuthenticationProvider  获取Authentication  这个类存了用户名, 密码, 权限, 是否过期 锁定等、然后才会调用 你的 controller 中的login方法, 

@SuppressWarnings("unchecked")
    @RequestMapping(value = { "/login", "/" })
    @ResponseBody
    public ModelAndView login(Model model)  {
        try {
            Authentication auth = SecurityContextHolder.getContext()
                    .getAuthentication();
            List<SimpleGrantedAuthority> auths=(List<SimpleGrantedAuthority>) auth.getAuthorities();
            //用户存在。验证码错误,返回登录页面,提示文字
            if(auths.get(0).getAuthority().equals(Role.ROLE_WRONGCODE.toString())){
                model.addAttribute("msg", "验证码不正确");
                model.addAttribute("mobile", auths.get(1).getAuthority());
                model.addAttribute("code", auths.get(2).getAuthority());
                model.addAttribute("status", 1);
                return new ModelAndView("login");
            }
            //用户不存在。跳转到登录页面,提示文字
            else if(auths.get(0).getAuthority().equals(Role.ROLE_TOURIST.toString())){
                model.addAttribute("msg", "该用户不存在");
                model.addAttribute("mobile", auths.get(1).getAuthority());
                model.addAttribute("code", auths.get(2).getAuthority());
                if(auths.get(1).getAuthority()!=null&&auths.get(2).getAuthority()!=null){
                model.addAttribute("status", 2);
                }
                return new ModelAndView("login");
            }
            if (auth instanceof AnonymousAuthenticationToken) {
                return new ModelAndView("login");
            } else {
                // 获取用户登录权限详细
                Object pinciba = auth.getPrincipal();
                if (pinciba instanceof UserDetails) {
                    UserDetails userDetail = ((UserDetails) pinciba);
                    model.addAttribute("username", userDetail.getUsername());
                    Customer u = userService
                            .getUserByname(userDetail.getUsername());
                    // 用户角色
                    model.addAttribute("role", u.getRole());

                    String today = new DateTime().toString("yyyy-MM-dd");
                    // 今天收益
                    Double todayIncome = indexService.getTodayIncome(today);
                    // 今天总充值金额
                    Double buyInCome = indexService.getBuyIncome(today);
                    // 今天新增用户数
                    Integer dayCount = indexService.findDayCount(today);
                    // 今天累计用户数
                    Integer dayAllCount = indexService.findDayAllCount(today);
                    model.addAttribute("todayIncome",
                            todayIncome == null ? 0.00 + "元" : todayIncome
                                    + "元");
                    model.addAttribute("buyInCome",
                            buyInCome == null ? 0.00 + "元" : buyInCome + "元");
                    model.addAttribute("dayCount", dayCount == null ? 0 + "人"
                            : dayCount + "人");
                    model.addAttribute("dayAllCount", dayAllCount + "人");
                }

                // 登录成功跳到主页
                return new ModelAndView("home");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ModelAndView("login");
        }

    }

 

===========================开发过程中发现一个问题, 就是springsecurity 的异常怎么在页面接受, 百度了很多资料, 说用EL表达式 ${SPRING_SECURITY_LAST_EXCEPTION.message} 获取, 可惜我不能获取

主要是因为登录的时候用form  有两种 提交方式:

 1 form提交, 按钮为submit , 这是springsecurity 默认配置, 就会先去调用  AuthenticationProvider  获取权限再 调login方法, 但是回参不好在返回到页面,

2 ajax 提交, 但是不走 AuthenticationProvider  ,

最后我把 错误信息放到 Authentication 。 它 会带到我的controller 里面, 然后 返回个新页面, 再 把 参数带过去:

 

以下 是html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
    <meta name="description" content=""/>
    <meta name="author" content="ThemeBucket"/>
    <link rel="shortcut icon" href="#" type="image/png"/>
    <title>全民发布</title>
      <link href="/bootstrap/css/loginstyle.css" rel="stylesheet"/>
    <link href="/bootstrap/css/style-responsive.css" rel="stylesheet"/>
        <script src="/bootstrap/js/modernizr.min.js"></script>
    <link rel="stylesheet" href="/bootstrap/css/font-awesome.min.css"/>
    <script src="/plugins/jQuery/jquery-2.2.3.min.js"></script>
    <script src="/bootstrap/js/bootstrap.min.js"></script>
     <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css"/>
     <link href="/bootstrap/css/bootstrapValidator.min.css" rel="stylesheet"/>
    <script src="/bootstrap/js/bootstrapValidator.js"></script>

  
</head>

<body class="login-body">

<div class="container">
       
    <form class="form-signin" th:action="@{/login}" method="post" id="loginForm">
    <input type="hidden" th:value="${mobile}" id="mobile"/>
        <input type="hidden" th:value="${msg}" id="msg"/>
        <input type="hidden" th:value="${code}" id="code"/>
        <div class="form-signin-heading text-center">
            <h1 class="sign-title">登录</h1>
            <img src="http://apps.ycmedia.cn/qm/img/lable/120x80/00.png?ver=1" alt=""/>
        </div>
        <div class="login-wrap">
            <input id="username" name="username" type="text" placeholder="手机号码" class="form-control" th:value="${mobile}"/>
              <span id="telephonenameTip"></span>
                 <div class="row"  th:if="${status==2}">
                                  <font color="red" th:text="${msg}" style="margin-left: 17px;"></font>         
               </div>
            <button type="button" class="btn btn-info" style="margin-left: 82%;margin-bottom: 12px;" id="getcode" >发送</button>
            <input id="" name="password" type="text" placeholder="验证码" class="form-control" th:value="${code}"/>
              <div class="row"  th:if="${status==1}">
                                  <font color="red" th:text="${msg}" style="margin-left: 17px;"></font>         
               </div>
            
            
            <button class="btn btn-lg btn-login btn-block" type="submit">
                <i class="fa fa-check"></i>
            </button>

            <div class="registration">
                还不是一个用户?
                <a class=""  th:href="@{/registration}">
                    注册
                </a>
            </div>
            <label class="checkbox">
                <input type="checkbox" value="remember-me"/> 记住我
                <span class="pull-right">
                    <a data-toggle="modal" href="#myModal"> 忘记密码?</a>

                </span>
            </label>

        </div>

        <!-- Modal -->
        <div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="myModal" class="modal fade">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title">Forgot Password ?</h4>
                    </div>
                    <div class="modal-body">
                        <p>Enter your e-mail address below to reset your password.</p>
                        <input type="text" name="email" placeholder="Email" autocomplete="off" class="form-control placeholder-no-fix"/>

                    </div>
                    <div class="modal-footer">
                        <button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
                        <button class="btn btn-primary" type="button">Submit</button>
                    </div>
                </div>
            </div>
        </div>
        <!-- modal -->

    </form>

</div>
<script type="text/javascript">
window.onload = function () {
    $(':input','#loginForm')  
     .not(':button, :submit, :reset, :hidden')  
     .val('')  
     .removeAttr('checked')  
     .removeAttr('selected'); 
    //短信验证码  
    var InterValObj; //timer变量,控制时间    
    var count = 60; //间隔函数,1秒执行    
    var curCount;//当前剩余秒数    
    var code = ""; //验证码    
    var codeLength = 6;//验证码长度   

    $("#getcode").click(function () {
        //获取输入的手机号码
        var phoNum = $("#username").val();
         var regrep=/^1[3|4|5|7|8][0-9]{9}$/;
         
         if(!regrep.test(phoNum)){
              $("#telephonenameTip").html('<font color="red">手机号码格式不正确 </font>');
             return;
         }
   
        curCount = count;
        // 设置按钮显示效果,倒计时   
        $("#getcode").attr("disabled", "true");
        $("#getcode").val("请在" + curCount + "秒内输入验证码");
        InterValObj = window.setInterval(SetRemainTime, 1000); // 启动计时器,1秒执行一次    

        // 向后台发送处理数据    
        $.ajax({
            type: "get", // 用POST方式传输    
            dataType: "json", // 数据格式:JSON    
            url: "http://testi.xf120.com/qm/sms/send?mobile="+phoNum, // 目标地址    
            error: function (msg) {
                 $("#telephonenameTip").html('<font color="red">× 短信验证码发送失败,请重新发送 </font>');
                alert(msg);
            },
            success: function (data) {
                 $("#telephonenameTip").html('<font color="green">√ 短信验证码已发到您的手机,请查收(15分钟内有效)</font>');
              
            }
        });

    });

    //timer处理函数    
    function SetRemainTime() {
        if (curCount == 0) {
            window.clearInterval(InterValObj);// 停止计时器    
            $("#getcode").removeAttr("disabled");// 启用按钮    
            $("#getcode").val("重新发送验证码");
            code = ""; // 清除验证码。如果不清除,过时间后,输入收到的验证码依然有效    
        } else {
            curCount--;
            $("#getcode").val("请在" + curCount + "秒内输入验证码");
        }
    }
    
   
     

}

</script>


</body>

</html>

 

 

===================================================== 大概搞定了=============以下是效果图

 

posted @ 2016-11-04 17:12  猪哥哥厉害  阅读(16329)  评论(2编辑  收藏  举报