参数:用户名username,密码password
思路:首先先校验从前端输入的用户名是否存在,如果不存在,则从后端返回一个错误信息status=1,msg=“用户名不存在”告知前端。如果校验用户名存在,则继续校验密码是否输入正确,不正确,返回一个错误信息status=1,msg=“密码错误”告知前端。否则,则登录成功,然后把用户的信息存在session中,返回用户的信息至前端。
@RequestMapping(value="login.do",method= RequestMethod.POST)
@ResponseBody
public ServerResponse login(String username, String password, HttpSession session){
ServerResponse response=iUserService.login(username,password);
if(response.isSuccess()){
//把当前用户的信息加到session中
session.setAttribute(Const.CURRENT_USER,response.getData());
}
return response;
}
//用户登录
ServerResponse login(String username, String password);
@Override
public ServerResponse login(String username, String password) {
//先检查用户名是否存在
int resultCount=userMapper.checkUsername(username);
if(resultCount==0){
return ServerResponse.createByErrorMessage("用户名不存在");
}
//用户名存在,则判断密码是否正确,密码使用MD5加密
String md5Password =MD5Util.MD5EncodeUtf8(password);
User user=userMapper.selectLogin(username,md5Password);
if(user==null){
return ServerResponse.createByErrorMessage("密码错误");
}
//用户名和密码都正确,则登录成功
user.setPassword(org.apache.commons.lang3.StringUtils.EMPTY);
return ServerResponse.createBySuccess("登录成功",user);
}
{
"status": 0,
"msg": "登录成功",
"data":{
"id": 22,
"username": "why",
"password": "",
"email": "[email protected]",
"phone": "15298945101",
"question": "问题",
"answer": "答案",
"role": 0,
"createTime": 1561799744000,
"updateTime": 1561910042000
}
}
输入密码错误
{
"status": 1,
"msg": "密码错误"
}
输入用户名错误
{
"status": 1,
"msg": "用户名不存在"
}
参数:User
思路:首先校验username和email是否被注册过,如果用户名被注册过,则从后端返回一个错误信息status=1,msg=“用户名已存在”告知前端。如果邮箱被注册过,则从后端返回一个status=1,msg=“邮箱已存在”告知前端。反之则注册成功。
//校验
//type表示传过来的username还是email
//str表示传过来的value值
@RequestMapping(value = "check_valid.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse checkValid(String str,String type){
return iUserService.checkValid(str,type);
}
//用户注册
@RequestMapping(value = "register.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse register(User user){
return iUserService.register(user);
}
//注册
ServerResponse register(User user);
//校验用户名和邮箱
ServerResponse checkValid(String str,String type);
/*
校验用户名和邮箱是否被注册过
type表示传过来的是username还是email
str表示传过来的value值
例如:/check_valid.do?str=why&type=username
把用户名已存在或者邮箱已存在回应至前端
*/
public ServerResponse checkValid(String str,String type){
//传过来的type不为空,判断type是否不为空,不为空则true
if(org.apache.commons.lang3.StringUtils.isNotBlank(type)){
//开始校验
if(Const.USERNAME.equals(type)){
int resultCount = userMapper.checkUsername(str);
if (resultCount > 0) {
return ServerResponse.createByErrorMessage("用户名已存在");
}
}
if(Const.EMAIL.equals(type)){
int resultCount = userMapper.checkEmail(str);
if (resultCount > 0) {
return ServerResponse.createByErrorMessage("邮箱已存在");
}
}
}else {
return ServerResponse.createByErrorMessage("参数错误");
}
//否则用户名和密码不存在,说明校验成功,可以进行注册
return ServerResponse.createBySuccessMessage("校验成功");
}
注册的register方法调用checkValid方法校验用户名和邮箱是否已存在
//注册
public ServerResponse register(User user) {
//验证用户名是否被注册
ServerResponse vaildResponse=this.checkValid(user.getUsername(),Const.USERNAME);
if(!vaildResponse.isSuccess()){
return vaildResponse;
}
//用户名不存在,则判断验证邮箱是否被注册
vaildResponse=this.checkValid(user.getEmail(),Const.EMAIL);
if(!vaildResponse.isSuccess()){
return vaildResponse;
}
//设置用户角色
user.setRole(Const.Role.ROLE_CUSTOMER);
//设置MD5密码
user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword()));
//插入用户信息
int resultCount=userMapper.insert(user);
if(resultCount==0){
return ServerResponse.createByErrorMessage("注册失败");
}
return ServerResponse.createBySuccessMessage("注册成功");
}
{
"status": 0,
"msg": "注册成功"
}
{
"status": 1,
"msg": "用户名已存在"
}
{
"status": 1,
"msg": "邮箱已存在"
}
//获取用户登录信息
@RequestMapping(value = "get_user_info.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse getUserInfo(HttpSession session){
//从session中获取
User user= (User) session.getAttribute(Const.CURRENT_USER);
if(user!=null){
return ServerResponse.createBySuccess(user);
}
return ServerResponse.createByErrorMessage("用户未登录,无法获取用户登录信息");
}
{
"status": 0,
"data":{
"id": 22,
"username": "why",
"password": "",
"email": "[email protected]",
"phone": "15298945101",
"question": "问题",
"answer": "答案",
"role": 0,
"createTime": 1561799744000,
"updateTime": 1561910042000
}
}
{
"status": 1,
"msg": "用户未登录,无法获取用户登录信息"
}
(1)忘记密码问题的获取
参数:用户名username
思路:首先校验用户名是否存在,不存在则从后端返回一个错误信息status=1,msg=“用户不存在”告知前端。反之从数据库里以username为查询条件,查找出此用户忘记密码的问题返回至前端。
//忘记密码问题的获取
//localhost:8080/user/forget_get_question.do?username=why
@RequestMapping(value = "forget_get_question.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse forgetGetQuestion(String username){
return iUserService.selectQuestion(username);
}
//忘记密码问题的获取
ServerResponse selectQuestion(String username);
//忘记密码问题的获取
//localhost:8080/user/forget_get_question.do?username=why
public ServerResponse selectQuestion(String username){
//检验用户名是否存在,再按下一步按钮,就会出现请输入密码提示答案的框
ServerResponse validResponse=this.checkValid(username,Const.USERNAME);
//调用注册校验的方法,如果返回值为true,则说明用户名不存在
if(validResponse.isSuccess()){
return ServerResponse.createByErrorMessage("用户不存在");
}
String question=userMapper.selectQuestionByUsername(username);
//问题不为空
if(org.apache.commons.lang3.StringUtils.isNotBlank(question)){
return ServerResponse.createBySuccess(question);
}
return ServerResponse.createByErrorMessage("该用户未设置找回密码问题");
}
{
"status": 0,
"data": "问题"
}
{
"status": 1,
"msg": "该用户未设置找回密码问题"
}
(2)校验忘记密码中问题答案是否正确
参数:用户名username,问题question,答案answer
思路:首先以username,question,answer作为查询条件,如果查询的结果大于0,则说明从前端传来的问题的答案是正确的。此时为了防止横向越权(横向越权指的是攻击者尝试访问与他拥有相同权限的用户的资源 ),答案正确则生成一个随机的且唯一的UUID且返回至前端,以该用户名和此UUID作为一对键值对存入guava构建的本地缓存中(key为用户名,value为UUID),并且UUID存在缓存中有时间限制,超过设置的规定时间,则UUID过期变为无效。在设置新密码的时候根据此用户名取出对应的UUID。
public class TokenCache {
//声明日志
private static Logger logger= LoggerFactory.getLogger(TokenCache.class);
public static final String TOKEN_PREFIX="token_";
//guava缓存
//声明静态的内存块
//initialCapacity为缓存的初始化容量
// maximumSize缓存的最大容量,当超过这个容量,guava的cache就会使用LRU算法
//缓存的有效期为12个小时
private static LoadingCache localCache= CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS).build(new CacheLoader() {
@Override
//默认的数据加载实现,当调用get取值的时候,如果key没有对应的值,就调用这个方法进行加载
public String load(String s) throws Exception {
return "null";
}
});
public static void setKey(String key,String value){
localCache.put(key, value);
}
public static String getKey(String key){
String value=null;
try{
value=localCache.get(key);
if ("null".equals(value)){
return null;
}
return value;
}catch (Exception e){
logger.error("localCache get error",e);
}
return null;
}
}
//提交问题的答案,校验问题答案是否正确
//localhost:8080/user/forget_check_answer.do?username=why&question=问题&answer=答案
@RequestMapping(value = "forget_check_answer.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse forgetCheckAnswer(String username,String question,String answer){
return iUserService.checkAnswer(username,question,answer);
}
//校验忘记密码问题的答案是否正确
ServerResponse checkAnswer(String username,String question,String answer);
//利用guava缓存
//忘记密码中重置密码的校验问题的答案是否正确
//localhost:8080/user/forget_check_answer.do?username=why&question=答案&answer=问题
public ServerResponse checkAnswer(String username,String question,String answer){
int resultCount=userMapper.checkAnswer(username,question,answer);
if(resultCount>0){
//回答正确,则生成唯一的UUID,防止横向越权和纵向越权
String forgetToken= UUID.randomUUID().toString();
//把forgetToken放到本地cache中
//把UUID返回前端
TokenCache.setKey(TokenCache.TOKEN_PREFIX+username,forgetToken);
return ServerResponse.createBySuccess(forgetToken);
}
return ServerResponse.createByErrorMessage("问题答案错误");
}
{
"status": 0,
"data": "27df4461-5dc3-412c-b16b-39669cf4eb6d"
}
{
"status": 1,
"msg": "问题答案错误"
}
(3)忘记密码中设置新的密码
参数:用户名username,新密码passwordNew,UUID
思路:首先判断从前端传来的UUID是否为空,为空则从后端返回一个错误信息status=1,msg=“参数错误,token需要传递”告知前端。再判断用户名是否存在。然后根据传过来的username从缓存中取出此username的UUID,然后判断此UUID是否为空,如果为空则说明此UUID超过设置的规定时间,则被清空。如果从缓存中取出的UUID没有超过有效期,则判断此UUID与从前端传来的UUID是否一致,一致则在数据库中设置新密码,反之设置密码失败。
//忘记密码中的重置密码
//localhost:8080/user/forget_reset_password.do?username=why&passwordNew=xxx&forgetToken=27df4461-5dc3-412c-b16b-39669cf4eb6d
@RequestMapping(value = "forget_reset_password.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse forgetResetPassword(String username,String passwordNew,String forgetToken){
return iUserService.forgetRestPassword(username, passwordNew, forgetToken);
}
//忘记密码中的重置密码
ServerResponse forgetRestPassword(String username,String passwordNew,String forgetToken);
//忘记密码中的重置密码
//localhost:8080/user/forget_reset_password.do?username=why&passwordNew=xxx&forgetToken=27df4461-5dc3-412c-b16b-39669cf4eb6d
public ServerResponse forgetRestPassword(String username,String passwordNew,String forgetToken){
//判断forgetToken是否为空,如果为空,则参数错误
if(org.apache.commons.lang3.StringUtils.isBlank(forgetToken)){
return ServerResponse.createByErrorMessage("参数错误,token需要传递");
}
ServerResponse validResponse=this.checkValid(username,Const.USERNAME);
//调用注册校验的方法,如果返回值为true,则说明用户名不存在
if(validResponse.isSuccess()){
return ServerResponse.createByErrorMessage("用户不存在");
}
//如果用户名存在,则从缓存中取出该用户名回答问题中存的UUID
String token=TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
//对token进行校验,如果超过缓存规定的存放时间,则token则被清空
if(org.apache.commons.lang3.StringUtils.isBlank(token)){
return ServerResponse.createByErrorMessage("token过期或者无效");
}
if (org.apache.commons.lang3.StringUtils.equals(forgetToken,token)){
String md5Password=MD5Util.MD5EncodeUtf8(passwordNew);
int rowCount=userMapper.updatePasswordByUsername(username,md5Password);
if(rowCount>0){
return ServerResponse.createBySuccessMessage("密码修改成功");
}else {
return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token");
}
}
return ServerResponse.createByErrorMessage("密码修改失败");
}
{
"status": 0,
"msg": "密码修改成功"
}
{
"status": 1,
"msg": "密码修改失败"
}
或者
{
"status": 1,
"msg": "token过期或者无效"
}
或者 此用户的UUID(token)没失效,但是从前端传来的token与缓存中取出来的不匹配
{
"status": 1,
"msg": "token错误,请重新获取重置密码的token"
}
参数:User,旧密码passwordOld,新密码passwordNew
思路:首先先校验是否为登录状态下,如果为登录状态下,则为了防止横向越权,则需要输入旧的密码,旧的密码正确,就设置新的密码。
//登录状态下的重置密码
@RequestMapping(value = "reset_password.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse resetPassword(HttpSession session,String passwordOld,String passwordNew){
User user= (User) session.getAttribute(Const.CURRENT_USER);
if (user==null){
return ServerResponse.createByErrorMessage("用户未登录");
}
return iUserService.resetPassword(passwordOld,passwordNew,user);
}
//登录状态下的重置密码
ServerResponse resetPassword(String passwordOld,String passwordNew,User user);
//登录状态下的重置密码,输入旧密码,新密码,再次确认新密码
public ServerResponse resetPassword(String passwordOld,String passwordNew,User user){
//防止横向越权,要校验一下这个用户的旧密码是否正确
int resultCount=userMapper.checkPassword(MD5Util.MD5EncodeUtf8(passwordOld),user.getId());
if (resultCount==0){
return ServerResponse.createByErrorMessage("旧密码错误");
}
user.setPassword(MD5Util.MD5EncodeUtf8(passwordNew));
int updateCount=userMapper.updateByPrimaryKeySelective(user);
if (updateCount>0){
return ServerResponse.createBySuccessMessage("密码更新成功");
}
return ServerResponse.createByErrorMessage("密码更新失败");
}
{
"status": 0,
"msg": "密码更新成功"
}
{
"status": 1,
"msg": "旧密码错误"
}
参数:userId
思路:判断用户是否登录,如果登录了,就以该用户的id为查询条件,查询出该用户的个人信息并返回至前端。
//获取用户的详细信息,前台上展示用户的个人信息以便用户修改
@RequestMapping(value = "get_information.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse get_information(HttpSession session){
User currentUser= (User) session.getAttribute(Const.CURRENT_USER);
if(currentUser==null){
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),"用户未登录,无法获取当前用户信息,status=10,强制登录");
}
return iUserService.getInformation(currentUser.getId());
}
//获取用户个人信息
ServerResponse getInformation(Integer userId);
//获取用户个人信息
public ServerResponse getInformation(Integer userId){
User user=userMapper.selectByPrimaryKey(userId);
if(user==null){
return ServerResponse.createByErrorMessage("找不到当前用户");
}
user.setPassword(org.apache.commons.lang3.StringUtils.EMPTY);
return ServerResponse.createBySuccess(user);
}
{
"status": 0,
"data":{
"id": 22,
"username": "why",
"password": "",
"email": "[email protected]",
"phone": "15298945101",
"question": "问题",
"answer": "答案",
"role": 0,
"createTime": 1561799744000,
"updateTime": 1561910042000
}
}
{
"status": 10,
"msg": "用户未登录,无法获取当前用户信息,status=10,强制登录"
}
参数:User
思路:判断用户是否登录,用户名不能被更改,修改邮箱要判断邮箱是否被注册过,修改成功则要更新session里的数据。
//更新个人用户信息
@RequestMapping(value = "update_information.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse update_information(HttpSession session,User user){
//判断是否为登录状态
User currentUser= (User) session.getAttribute(Const.CURRENT_USER);
if(currentUser==null){
return ServerResponse.createByErrorMessage("用户未登录");
}
user.setId(currentUser.getId());
user.setUsername(currentUser.getUsername());
ServerResponse response= iUserService.updateInformation(user);
if (response.isSuccess()){
//如果更新成功,则重新更改session中的个人信息
session.setAttribute(Const.CURRENT_USER,response.getData());
}
return response;
}
//更新个人用户信息
ServerResponse updateInformation(User user);
//修改个人信息
public ServerResponse updateInformation(User user){
//username是不能被更新的
//email也要被校验,检验新的email是否已经存在
int resultCount=userMapper.checkEmailByUserId(user.getEmail(),user.getId());
if(resultCount>0){
return ServerResponse.createByErrorMessage("email已经存在,请更换email再尝试更新");
}
User updateUser=new User();
updateUser.setId(user.getId());
updateUser.setUsername(user.getUsername());
updateUser.setEmail(user.getEmail());
updateUser.setPhone(user.getPhone());
updateUser.setQuestion(user.getQuestion());
updateUser.setAnswer(user.getAnswer());
int updateCount=userMapper.updateByPrimaryKeySelective(updateUser);
if (updateCount>0){
return ServerResponse.createBySuccess("更新个人信息成功",updateUser);
}
return ServerResponse.createByErrorMessage("更新个人信息失败");
}
{
"status": 0,
"msg": "更新个人信息成功"
}
{
"status": 1,
"msg": "更新个人信息失败"
}
//退出登录
@RequestMapping(value="logout.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse logout(HttpSession session){
//把当前用户的信息移出session
session.removeAttribute(Const.CURRENT_USER);
return ServerResponse.createBySuccessMessage("退出登录成功");
}
{
"status": 0,
"msg": "退出登录成功"
}
public interface UserMapper {
int deleteByPrimaryKey(Integer id);
int insert(User record);
int insertSelective(User record);
User selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
//检测用户名是否存在
int checkUsername(String username);
//验证登录,登录成功则返回用户的信息
//将请求中参数username的值赋值给变量username
User selectLogin(@Param("username") String username,@Param("password") String password);
//检查邮箱是否被注册
int checkEmail(String email);
//忘记密码问题的获取
String selectQuestionByUsername(String uername);
//校验忘记密码问题的答案
int checkAnswer(@Param("username") String username,@Param("question") String question,@Param("answer")String answer);
//忘记密码中的重置密码
int updatePasswordByUsername(@Param("username") String username,@Param("passwordNew") String passwordNew);
//登录状态下的重置密码
int checkPassword(@Param("password") String password,@Param("userId") Integer userId);
//根据ID查询email是否被使用注册
int checkEmailByUserId(@Param("email")String eamil,@Param("userId")Integer userId);
}
id, username, password, email, phone, question, answer, role, create_time, update_time
delete from mmall_user
where id = #{id,jdbcType=INTEGER}
insert into mmall_user (id, username, password,
email, phone, question,
answer, role, create_time,
update_time)
values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{question,jdbcType=VARCHAR},
#{answer,jdbcType=VARCHAR}, #{role,jdbcType=INTEGER}, now(),
now())
insert into mmall_user
id,
username,
password,
email,
phone,
question,
answer,
role,
create_time,
update_time,
#{id,jdbcType=INTEGER},
#{username,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{phone,jdbcType=VARCHAR},
#{question,jdbcType=VARCHAR},
#{answer,jdbcType=VARCHAR},
#{role,jdbcType=INTEGER},
now(),
now(),
update mmall_user
username = #{username,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR},
email = #{email,jdbcType=VARCHAR},
phone = #{phone,jdbcType=VARCHAR},
question = #{question,jdbcType=VARCHAR},
answer = #{answer,jdbcType=VARCHAR},
role = #{role,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=TIMESTAMP},
update_time =now(),
where id = #{id,jdbcType=INTEGER}
update mmall_user
set username = #{username,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR},
email = #{email,jdbcType=VARCHAR},
phone = #{phone,jdbcType=VARCHAR},
question = #{question,jdbcType=VARCHAR},
answer = #{answer,jdbcType=VARCHAR},
role = #{role,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=TIMESTAMP},
update_time = now()
where id = #{id,jdbcType=INTEGER}
update mmall_user
set password=#{passwordNew},update_time=now()
where username=#{username}