1. 程式人生 > 其它 >【認證服務】驗證碼、社交登入、分散式session、單點登入

【認證服務】驗證碼、社交登入、分散式session、單點登入

https://blog.csdn.net/hancoder/article/details/114242184

一.驗證碼

package com.xunqi.gulimall.auth.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class GulimallWebConfig implements WebMvcConfigurer { /**· * 檢視對映:傳送一個請求,直接跳轉到一個頁面 * @param registry */ @Override public void addViewControllers(ViewControllerRegistry registry) { // registry.addViewController("/login.html").setViewName("login"); registry.addViewController("/reg.html").setViewName("reg"); } }

(1) 驗證碼倒計時js

$(function () {
    $("#sendCode").click(function () {
        if ($(this).hasClass("disabled")) {
            // 1.進入倒計時效果
        } else {
            $.get("/sms/sendcode?phone=" + $("#phoneNum").val(), function (data) {
                if (data.code != 0) {
                    layer.msg(data.msg)
                }
            });
            
            
// 2.給指定手機號傳送驗證碼 timeoutChangeStyle() } }) }) // 外部變數計時 let num = 60; function timeoutChangeStyle() { $("#sendCode").attr("class", "disabled") if (num == 0) {//可以再次傳送 num = 60; $("#sendCode").attr("class", "");//取消disabled $("#sendCode").text("傳送驗證碼"); } else { var str = num + "s 後再次傳送"; $("#sendCode").text(str); // 1s後回撥 setTimeout("timeoutChangeStyle()", 1000); } num-- }

(2) 阿里雲-簡訊服務

@Data
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Component
public class SmsComponent {

    private String host;

    private String path;

    private String skin;

    private String sign;

    private String appCode;

    public String sendSmsCode(String phone, String code){
        String method = "GET";
        Map<String, String> headers = new HashMap<String, String>();
        //最後在header中的格式(中間是英文空格)為Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + this.appCode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("code", code);
        querys.put("phone", phone);
        querys.put("skin", this.skin);
        querys.put("sign", this.sign);
        HttpResponse response = null;
        try {
            response = HttpUtils.doGet(this.host, this.path, method, headers, querys);
            //獲取response的body
            if(response.getStatusLine().getStatusCode() == 200){
                return EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "fail_" + response.getStatusLine().getStatusCode();
    }
}
@Controller
@RequestMapping("/sms")
public class SmsSendController {

    @Autowired
    private SmsComponent smsComponent;

    /*** 提供給別的服務進行呼叫的
    該controller是發給簡訊服務的,不是驗證的
     */
    @GetMapping("/sendcode")
    public R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code){
        if(!"fail".equals(smsComponent.sendSmsCode(phone, code).split("_")[0])){
            return R.ok();
        }
        return R.error(BizCodeEnum.SMS_SEND_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_SEND_CODE_EXCEPTION.getMsg());
    }
}

傳送驗證碼:

@ResponseBody
    @GetMapping(value = "/sms/sendCode")
    public R sendCode(@RequestParam("phone") String phone) {

        //1、介面防刷
        String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
        if (!StringUtils.isEmpty(redisCode)) {
            //活動存入redis的時間,用當前時間減去存入redis的時間,判斷使用者手機號是否在60s內傳送驗證碼
            long currentTime = Long.parseLong(redisCode.split("_")[1]);
            if (System.currentTimeMillis() - currentTime < 60000) {
                //60s內不能再發
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMessage());
            }
        }

        //2、驗證碼的再次效驗 redis.存key-phone,value-code
        int code = (int) ((Math.random() * 9 + 1) * 100000);
        String codeNum = String.valueOf(code);
        String redisStorage = codeNum + "_" + System.currentTimeMillis();

        //存入redis,防止同一個手機號在60秒內再次傳送驗證碼
        stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX+phone,
                redisStorage,10, TimeUnit.MINUTES);

        thirdPartFeignService.sendCode(phone, codeNum);

        return R.ok();
    }

4) 後端JSR303校驗校驗

前端也可以進行校驗,此處是後端的驗證

@Data
public class UserRegisterVo {// JSR303校驗

    @Length(min = 6,max = 20,message = "使用者名稱長度必須在6-20之間")
    @NotEmpty(message = "使用者名稱必須提交")
    private String userName;

    @Length(min = 6,max = 20,message = "使用者名稱長度必須在6-20之間")
    @NotEmpty(message = "密碼必須提交")
    private String password;

    @NotEmpty(message = "手機號不能為空")
    @Pattern(regexp = "^[1]([3-9])[0-9]{9}$", message = "手機號格式不正確")
    private String phone;

    @NotEmpty(message = "驗證碼必須填寫")
    private String code;
}

前面的JSR303校驗怎麼用:

JSR303校驗的結果,被封裝到BindingResult,再結合BindingResult.getFieldErrors()方法獲取錯誤資訊,有錯誤就重定向至註冊頁面

@PostMapping("/register")
public String register(@Valid UserRegisterVo registerVo, 
                       BindingResult result,
                       RedirectAttributes attributes) {

    if (result.hasErrors()){
        return "redirect:http://auth.gulimall.com/reg.html";