Browse Source

添加找回密码接口

wangmh 8 years ago
parent
commit
0273159438

+ 17 - 3
sso-server/src/main/java/com/uas/sso/controller/LoginController.java

@@ -39,8 +39,21 @@ import java.util.*;
 @RestController
 public class LoginController extends BaseController {
 
+    /**
+     * 密码输错3次
+     */
     private static final int PWD_ERROR_FIVE_TIME = 5;
+
+    /**
+     * 密码输错3次
+     */
     private static final int PWD_ERROR_THREE_TIME = 3;
+
+    /**
+     * 登录验证码存session的key值
+     */
+    private static final String LOGIN_CAPTCHA = "loginCaptcha";
+
     @Autowired
     private AppService appService;
 
@@ -90,8 +103,8 @@ public class LoginController extends BaseController {
 
         // 校验账户密码输错次数
         int pwdErrorCount = user.getUserRecord() == null ? 0 : user.getUserRecord().getPwdErrorCount();
-        Object randomString = request.getSession().getAttribute("randomString");
-        String checkCode = randomString == null ? "" : randomString.toString();
+        Object loginCaptcha = request.getSession().getAttribute(LOGIN_CAPTCHA);
+        String checkCode = loginCaptcha == null ? "" : loginCaptcha.toString();
         if (pwdErrorCount >= PWD_ERROR_FIVE_TIME) {
             return error("403", "密码错误次数已达上限,今日无法登陆");
         }
@@ -301,7 +314,8 @@ public class LoginController extends BaseController {
     @RequestMapping(value = "/checkCode", method = RequestMethod.GET)
     public void checkCode() {
         try {
-            CaptchaUtil.outputCaptcha(request, response);
+            // 获取验证码
+            CaptchaUtil.outputCaptcha(request, response, LOGIN_CAPTCHA);
         } catch (ServletException e) {
             e.printStackTrace();
         } catch (IOException e) {

+ 5 - 0
sso-server/src/main/java/com/uas/sso/controller/PersonalRegisterController.java

@@ -91,6 +91,11 @@ public class PersonalRegisterController extends BaseController {
     @RequestMapping(value = "/checkCode", method = RequestMethod.GET)
     @ResponseBody
     public ModelMap getCode(String mobile) {
+        // 参数校验
+        if (StringUtils.isEmpty(mobile)) {
+            return error("请输入手机号");
+        }
+
         // 获取验证码
         String token = getMobileCode(mobile);
 

+ 345 - 0
sso-server/src/main/java/com/uas/sso/controller/ResetPasswordController.java

@@ -1,10 +1,29 @@
 package com.uas.sso.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.uas.message.mail.service.MailService;
+import com.uas.sso.SSOHelper;
+import com.uas.sso.SSOToken;
+import com.uas.sso.core.Const;
+import com.uas.sso.core.PasswordStrength;
+import com.uas.sso.core.Status;
+import com.uas.sso.entity.*;
 import com.uas.sso.service.UserService;
+import com.uas.sso.util.CaptchaUtil;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ui.ModelMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.servlet.ServletException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * 重置密码controller
  *
@@ -18,5 +37,331 @@ public class ResetPasswordController extends BaseController {
     @Autowired
     private UserService userService;
 
+    @Autowired
+    private MailService mailService;
+
+    /**
+     * 重置密码验证码存session的key
+     */
+    private static final String RESET_CAPTCHA = "resetCaptcha";
+
+    /**
+     * 类型 重置密码
+     */
+    private static final String TYPE_RESET = "reset";
+
+    /**
+     * 类型 修改密码
+     */
+    private static final String TYPE_UPDATE = "update";
+
+    /**
+     * token有效期
+     */
+    private static final int EXPIRES = 24*60*60;
+
+    /**
+     * 找回密码校验手机号
+     * 根据手机号获取用户信息,之后修改密码直接使用这个信息
+     *
+     * @param mobile
+     * @return
+     */
+    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
+    public ModelMap checkCaptcha(String mobile, String mobileArea, String captcha) {
+        // 校验手机号
+        User user = userService.findByMobile(mobile);
+        if (user == null) {
+            return error("用户不存在,请输入正确的手机号");
+        }
+
+        // 校验验证码
+        String resetCaptcha = (String) request.getSession().getAttribute(RESET_CAPTCHA);
+        if (StringUtils.isEmpty(resetCaptcha)) {
+            return error("未获取验证码");
+        }
+        if (!resetCaptcha.equals(captcha)) {
+            return error("请输入正确的验证码");
+        }
+
+        // 设置返回值
+        request.getSession().setAttribute("user", user);
+        return success();
+    }
+
+    /**
+     * 获取图片验证码
+     */
+    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.GET)
+    public void checkCaptcha() {
+        try {
+            // 获取验证码
+            CaptchaUtil.outputCaptcha(request, response, RESET_CAPTCHA);
+        } catch (ServletException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取可以校验方式
+     *
+     * @param type 修改密码类型
+     * @return
+     */
+    @RequestMapping(value = "/CheckType/{type}", method = RequestMethod.GET)
+    public ModelMap getCheckType(@PathVariable String type) {
+        // 找到用户信息
+        User user = null;
+        if (TYPE_RESET.equals(type)) {
+            // 调用类型为重置密码,重置密码可以通过session获得用户信息
+            user = (User) request.getSession().getAttribute("user");
+            if (user == null) {
+                return error("请求超时,请刷新重试!");
+            }
+        } else if (TYPE_UPDATE.equals(type)) {
+            // 调用类型为修改密码,修改密码可以通过cookie获得用户信息
+            SSOToken token = SSOHelper.getToken(request);
+            UserAccount userAccount = JSON.parseObject(token.getData(), UserAccount.class);
+            user = userService.findOne(userAccount.getUserUU());
+        }
+
+        // 设置返回数据
+        ModelMap data = new ModelMap();
+        data.put("mobile", Status.AUTHENTICATED.getCode() == user.getMobileValidCode() ? user.getMobile() : null);
+        data.put("email", Status.AUTHENTICATED.getCode() == user.getEmailValidCode() ? user.getEmail() : null);
+        request.getSession().setAttribute("user", user);
+        return success();
+    }
+
+    /**
+     * 重置密码第一步设置token
+     * @param userUU 用户uu号
+     * @return tokenId
+     */
+    private String setToken(Long userUU) {
+
+        Token token = new Token(userUU, EXPIRES);
+        return token.getId();
+    }
+
+    /**
+     * 通过密码重置密码
+     * @param password 密码
+     * @return
+     */
+    @RequestMapping(value = "/check/password", method = RequestMethod.POST)
+    public ModelMap checkByPassword(String password) {
+        // 通过session获取当前找回密码的用户
+        User user = (User) request.getSession().getAttribute("user");
+        if (StringUtils.isEmpty(user)) {
+            return error("请求超时,请刷新重试!");
+        }
+
+        // 校验密码
+        String encryPwd = userService.getEncryPassword(Const.ENCRY_FORMAT, password, user.getSalt());
+        if (!encryPwd.equals(password)) {
+            return error("密码错误");
+        }
+
+        // 设置token,并返回
+        String tokenId = setToken(user.getUserUU());
+        return success(new ModelMap("token", tokenId));
+    }
+
+    /**
+     * 通过手机号重置密码,获取验证码
+     * @return
+     */
+    @RequestMapping(value = "/check/mobile", method = RequestMethod.GET)
+    public ModelMap checkByMobile() {
+        // 从session中获取用户信息
+        User user = (User) request.getSession().getAttribute("user");
+        if (StringUtils.isEmpty(user)) {
+            return error("请求超时,请刷新重试!");
+        }
+
+        // 获取验证码
+        String token = getMobileCode(user.getMobile());
+
+        // 设置返回数据
+        ModelMap data = new ModelMap();
+        data.put("token", token);
+        request.getSession().setAttribute("token", token);
+        return success(data);
+    }
+
+    /**
+     * 通过手机号重置密码,校验验证码
+     *
+     * @param code 用户输入的验证码
+     * @param token 验证码id
+     * @return
+     */
+    @RequestMapping(value = "/check/mobile", method = RequestMethod.POST)
+    public ModelMap checkByMobile(String code, String token) {
+        // 从session中获取用户信息
+        User user = (User) request.getSession().getAttribute("user");
+        if (StringUtils.isEmpty(user)) {
+            return error("请求超时,请刷新重试!");
+        }
+
+        // 校验token是否正确
+        String sessionToken = (String) request.getSession().getAttribute("token");
+        if (StringUtils.isEmpty(sessionToken) || sessionToken.equals(token)) {
+            return error("请重新获取验证码");
+        }
+        if (StringUtils.isEmpty(code)) {
+            return error("请输入验证码");
+        }
+
+        // 校验验证码并删除token
+        checkMobileCode(token, user.getMobile(), code);
+        tokenService.delete(token);
+
+        // 设置token,并返回
+        String tokenId = setToken(user.getUserUU());
+        return success(new ModelMap("token", tokenId));
+    }
+
+    /**
+     * 通过邮箱重置密码,发送邮箱确认
+     *
+     * @return
+     */
+    @RequestMapping(value = "/check/email", method = RequestMethod.GET)
+    public ModelMap checkByEmail() {
+        // 从session中获取用户信息
+        User user = (User) request.getSession().getAttribute("user");
+        if (StringUtils.isEmpty(user)) {
+            return error("请求超时,请刷新重试!");
+        }
+
+        // 设置发送邮件信息
+        int expires = 24*60*60;
+        Token token = new Token("user", expires);
+        ModelMap data = new ModelMap();
+        data.put("vipName", user.getVipName());
+        // TODO 邮件认证地址
+        data.put("url", "http://192.168.253.66:8081/sso/resetPwd/check/question?token="+token);
+
+        // 发送邮件
+        String email = user.getEmail();
+        if (!StringUtils.isEmpty(email)) {
+            Setting mailTplId = settingService.findOne("templateForSendMailWhenResetPassword");
+            if (!StringUtils.isEmpty(mailTplId)) {
+                mailService.send(mailTplId.getValue(), email, data);
+            }
+        }
+
+        return success();
+    }
+
+    /**
+     * 重置密码第二步,认证密保
+     * @param token
+     * @return
+     */
+    @RequestMapping(value = "/check/question", method = RequestMethod.GET)
+    public ModelMap checkByQuestion(String token) {
+        // 校验token
+        if (StringUtils.isEmpty(token)) {
+            return error("请刷新重试");
+        }
+        Token existToken = tokenService.findOne(token);
+        if (existToken == null) {
+            return error("认证信息已过期,清刷新重试!");
+        }
+
+        // 查询密保
+        Long userUU = (Long) existToken.getBind();
+        User user = userService.findOne(userUU);
+        if (user == null) {
+            return error("认证信息错误,清刷新重试!");
+        }
+        tokenService.delete(token);
+
+        // 返回用户密保,token
+        existToken = new Token(user, EXPIRES);
+        ModelMap data = new ModelMap();
+        data.put("token",existToken.getId());
+        data.put("question", user.getQuestions());
+        return success(data);
+    }
+
+
+    /**
+     * 重置密码第二步,认证密保
+     * @param token
+     * @return
+     */
+    @RequestMapping(value = "/check/question", method = RequestMethod.POST)
+    public ModelMap checkByQuestion(String token, List<Map<String, Object>> answers) {
+        // 校验token是否正确
+        if (StringUtils.isEmpty(token)) {
+            return error("请刷新重试");
+        }
+        Token expireToken = tokenService.findOne(token);
+        if (expireToken == null) {
+            return error("请求超时,请刷新重试");
+        }
+
+        // 校验密保答案
+        User user = (User) expireToken.getBind();
+        List<UserQuestion> questions = user.getQuestions();
+        Map<Long, String> userAnswer = new HashMap<>(questions.size());
+        for (UserQuestion question : questions) {
+            userAnswer.put(question.getId(), question.getAnswer());
+        }
+        for (Map<String, Object> answer : answers) {
+            if (!answer.get("answer").equals(userAnswer.get(answer.get("id")))){
+                return error("答案错误");
+            }
+        }
+
+        tokenService.delete(token);
+
+        // 返回token
+        expireToken = new Token(user, EXPIRES);
+        ModelMap data = new ModelMap();
+        data.put("token", expireToken.getId());
+        return success(data);
+    }
+
+    /**
+     * 重置密码第三步,重置密码
+     * @param password 新密码
+     * @param token tokenId,包含用户信息
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.POST)
+    public ModelMap resetPassword(String password, String token) {
+        // 校验token是否正确
+        if (StringUtils.isEmpty(token)) {
+            return error("请刷新重试");
+        }
+        Token expireToken = tokenService.findOne(token);
+        if (expireToken == null) {
+            return error("请求超时,请刷新重试");
+        }
+
+        // 校验密码
+        PasswordStrength passwordStrength = checkPasswordLevel(password);
+        if (PasswordStrength.WEAK.getValue() == passwordStrength.getValue()) {
+            return error("密码须为8-20字符的英文、数字混合");
+        }
+
+        // 从token中获取用户信息
+        User user = (User) expireToken.getBind();
+
+        // 设置加密后的密码
+        String encryPasswird = userService.getEncryPassword(Const.ENCRY_FORMAT, password, user.getSalt());
+        user.setPassword(encryPasswird);
+        userService.save(user);
 
+        // 删除token,返回成功
+        tokenService.delete(token);
+        return success();
+    }
 }

+ 2 - 5
sso-server/src/main/java/com/uas/sso/controller/UserManagerController.java

@@ -1,13 +1,11 @@
 package com.uas.sso.controller;
 
-import com.uas.sso.entity.User;
 import com.uas.sso.service.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
  * 用户信息管理controller
@@ -15,7 +13,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
  * @author wangmh
  * @date 2018/1/2
  */
-@Controller
+@RestController
 @RequestMapping("/api/user")
 public class UserManagerController extends BaseController {
 
@@ -29,7 +27,6 @@ public class UserManagerController extends BaseController {
      * @return
      */
     @RequestMapping(value = "/checkMobile", method = RequestMethod.GET)
-    @ResponseBody
     public ModelMap checkMobile(String mobile) {
         return new ModelMap("hasRegister", userService.mobileHasRegistered(mobile));
     }

+ 16 - 0
sso-server/src/main/java/com/uas/sso/entity/User.java

@@ -3,6 +3,7 @@ package com.uas.sso.entity;
 import javax.persistence.*;
 import java.io.Serializable;
 import java.sql.Timestamp;
+import java.util.List;
 
 /**
  * 用户信息
@@ -174,6 +175,13 @@ public class User implements Serializable {
     @JoinColumn(name = "record_id")
     private UserRecord userRecord;
 
+    /**
+     * 密保问题
+     */
+    @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE})
+    @JoinColumn(name = "useruu", nullable = false)
+    private List<UserQuestion> questions;
+
     public User() {
     }
 
@@ -384,4 +392,12 @@ public class User implements Serializable {
     public void setUserRecord(UserRecord userRecord) {
         this.userRecord = userRecord;
     }
+
+    public List<UserQuestion> getQuestions() {
+        return questions;
+    }
+
+    public void setQuestions(List<UserQuestion> questions) {
+        this.questions = questions;
+    }
 }

+ 91 - 0
sso-server/src/main/java/com/uas/sso/entity/UserQuestion.java

@@ -0,0 +1,91 @@
+package com.uas.sso.entity;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * @author uas
+ * @date 2018/1/10.
+ */
+@Entity
+@Table(name = "sso$user$question")
+public class UserQuestion implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @Column(name = "_id")
+    @SequenceGenerator(name = "sso$user$question_gen", sequenceName = "sso$user$question_seq", allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "sso$user$question_gen")
+    private Long id;
+
+    /**
+     * 用户uu号
+     */
+    @Column(name = "useruu")
+    private Long userUU;
+
+    /**
+     * 密保问题
+     */
+    @Column(name = "question")
+    private String question;
+
+    /**
+     * 密保答案
+     */
+    @Column(name = "answer")
+    private String answer;
+
+    /**
+     * 排序
+     */
+    @Column(name = "sort")
+    private String sort;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getUserUU() {
+        return userUU;
+    }
+
+    public void setUserUU(Long userUU) {
+        this.userUU = userUU;
+    }
+
+    public String getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(String question) {
+        this.question = question;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public String getSort() {
+        return sort;
+    }
+
+    public void setSort(String sort) {
+        this.sort = sort;
+    }
+}

+ 9 - 1
sso-server/src/main/java/com/uas/sso/service/UserService.java

@@ -78,7 +78,7 @@ public interface UserService {
      *
      * @param mobile 登录的手机号
      * @param password 密码
-     * @param isEncry 密码是否加密
+     * @param isEncry password密码是否加密
      */
     void checkPasswordByMobile(String mobile, String password, boolean isEncry);
 
@@ -113,4 +113,12 @@ public interface UserService {
      * @param userRecord
      */
     void save(UserRecord userRecord);
+
+    /**
+     * 根据用户uu号查找用户
+     *
+     * @param userUU 用户uu号
+     * @return
+     */
+    User findOne(Long userUU);
 }

+ 5 - 0
sso-server/src/main/java/com/uas/sso/service/impl/UserServiceImpl.java

@@ -205,4 +205,9 @@ public class UserServiceImpl implements UserService {
     public void save(UserRecord userRecord) {
         userRecordDao.save(userRecord);
     }
+
+    @Override
+    public User findOne(Long userUU) {
+        return userDao.findOne(userUU);
+    }
 }

+ 10 - 2
sso-server/src/main/java/com/uas/sso/util/CaptchaUtil.java

@@ -64,14 +64,22 @@ public class CaptchaUtil {
                 255 - c.getBlue());
     }
 
-    public static void outputCaptcha(HttpServletRequest request, HttpServletResponse response)
+    /**
+     *
+     * @param request
+     * @param response
+     * @param key 放到session中的key值
+     * @throws ServletException
+     * @throws IOException
+     */
+    public static void outputCaptcha(HttpServletRequest request, HttpServletResponse response, String key)
             throws ServletException, IOException
     {
 
         response.setContentType("image/jpeg");
 
         String randomString = getRandomString();
-        request.getSession(true).setAttribute("randomString", randomString);
+        request.getSession(true).setAttribute(key, randomString);
 
         int width = 100;
         int height = 30;