• 用户模块


    功能:

    1.登录

    controller层实现:

    从前端获取传入的用户名和密码,然后通过service进行具体的业务层校验,如果通过校验,则将此时的sessionId作为token值写入cookie中,然后将登录信息写入redis中,key是sessionId,value是具体的登录信息,并设置有效期。

     1     @RequestMapping(value = "login.do", method = RequestMethod.POST)
     2     @ResponseBody
     3     public ServerResponse<User> login(String username, String password, HttpSession session, HttpServletResponse httpServletResponse) {
     4         ServerResponse<User> response = iUserService.login(username, password);
     5         if(response.isSuccess()) {
     6             CookieUtil.writeLoginToken(httpServletResponse, session.getId());
     7             //sessionId是key,用户的登录信息是value,存在redis中
     8             //sessionId是tomcat中自动生成的,针对当前项目,每启动一次,sessionId就变一次
     9             //设置session超时时间
    10             RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()), Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
    11 
    12         }
    13         return response;
    14     }
    View Code

    service层实现:

    先校验用户名是否存在,如果存在,再将输入的密码进行md5加密,再去校验密码是否正确,再返回校验结果。

     1     public ServerResponse<User> login(String username, String password) {
     2         //校验用户名是否存在,如果存在,查询结果会返回1,因为用户名唯一;否则返回0
     3         int resultCount = userMapper.checkUsername(username);
     4         if (resultCount == 0) {
     5             return ServerResponse.createByErrorMessage("用户名不存在");
     6         }
     7         //密码登录MD5,将密码加密后再与数据库中的密码进行比对,因为数据库中存的不是明文密码,是md5加密后的密码
     8         String md5Password = MD5Util.MD5EncodeUtf8(password);
     9         //这里不是根据用户名校验密码是否正确,而是将用户名和密码同时传入dao层,在数据库中一起校验是否有当前用户存在,如果存在表明校验通过返回该用户对象
    10         User user = userMapper.selectLogin(username, md5Password);
    11         if (user == null) {
    12             return ServerResponse.createByErrorMessage("密码错误");
    13         }
    14         //将返回给controller的密码置空,是为了不让其显示出来
    15         user.setPassword(StringUtils.EMPTY);
    16         //校验通过,返回user对象给controller进行显示
    17         return ServerResponse.createBySuccess("登录成功", user);
    18     }
    View Code

    2.注册

    controller层实现:

    1 @RequestMapping(value = "register.do", method = RequestMethod.POST)
    2     @ResponseBody
    3     public ServerResponse<String> register(User user) {
    4         return iUserService.register(user);
    5     }
    View Code

    service层实现:

    先校验用户名和email的唯一性,这个唯一性是由service层保证的,而不是数据库层面由unique决定的,然后对密码进行加密后,进入dao层插入数据库进行持久化操作。

     1     public ServerResponse<String> register(User user) {
     2         //因为下面的校验用户名和email具有相同的逻辑,所以可以集成放在一个函数中,即checkValid函数,用第二个参数辨别传入的是用户名还是email,然后再校验
     3         //校验用户名是否已经存在
     4         ServerResponse validResponse = this.checkValid(user.getUsername(), Const.USERNAME);
     5         if (!validResponse.isSuccess()) {
     6             return validResponse;
     7         }
     8         //校验email是否已经存在
     9         validResponse = this.checkValid(user.getEmail(), Const.EMAIL);
    10         if (!validResponse.isSuccess()) {
    11             return validResponse;
    12         }
    13         //设置用户角色
    14         //这里是由前端决定注册的是普通用户还是管理员角色,因为不同的角色前端跳转的后台url是不一样的,以此后台来区分角色,所以这里直接将角色赋为customer。
    15         user.setRole(Const.Role.ROLE_CUSTOMER);
    16         //MD5加密,加密后再存入数据库       user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword()));
    17         //进入dao层进行插入操作
    18         int resultCount = userMapper.insert(user);
    19         if (resultCount == 0) {
    20             return ServerResponse.createByErrorMessage("注册失败");
    21         }
    22         return ServerResponse.createBySuccessMessage("注册成功");
    23     }
    View Code

    3.提交问题答案:

    controler层实现:

    1     @RequestMapping(value = "forget_check_answer.do", method = RequestMethod.POST)
    2     @ResponseBody
    3     public ServerResponse<String> forgetCheckAnswer(String username, String question, String answer) {
    4         return iUserService.checkAnswer(username, question, answer);
    5     }
    View Code

    service层实现:

    先校验问题的答案是否正确,如果正确,则生成一个UUID作为token值,存入redis中缓存,并设置有效期,然后将token值返回。

     1     public ServerResponse<String> checkAnswer(String username, String question, String answer) {
     2         //校验问题答案是否正确
     3         int resultCount = userMapper.checkAnswer(username, question, answer);
     4         if(resultCount > 0) {
     5             //说明问题及问题答案是这个用户的,并且是正确的
     6             //利用UUID创建无重复token
     7             String forgetToken = UUID.randomUUID().toString();
     8             //把token放入本地cache中,然后设置其有效期
     9         //    TokenCache.setKey(TokenCache.TOKEN_PREFIX + username, forgetToken);
    10 
    11             RedisShardedPoolUtil.setEx(Const.TOKEN_PREFIX + username, forgetToken, 60 * 60 * 12);
    12 
    13             //为什么这里调用的是泛型参数函数而不是string参数函数
    14             //因为函数名不同啊。。。
    15             return ServerResponse.createBySuccess(forgetToken);
    16         }
    17         return ServerResponse.createByErrorMessage("问题的答案错误");
    18     }
    View Code

    4.重置密码:

      1)登录状态下重置密码

      2)忘记密码后重置密码:如果不传入token,则很容易发生横向越权,即可以传任意用户名,然后将其密码重置,不需要通过问题校验。

    controler层实现:

    1     @RequestMapping(value = "forget_reset_password.do", method = RequestMethod.POST)
    2     @ResponseBody
    3     public ServerResponse<String> forgetResetPassword(String username, String passwordNew, String forgetToken) {
    4         return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
    5     }
    View Code

    service层实现:

    先校验token是否正确传入,然后校验用户名是否存在(因为是忘记密码重置),然后从redis中取出缓存的token值进行比对,如果相同则说明是同一用户,对新密码进行加密,然后持久化到数据库。

     1     public ServerResponse<String> forgetResetPassword(String username, String passwordNew, String forgetToken) {
     2         //校验token是否已经传递过来
     3         if(StringUtils.isBlank(forgetToken)) {
     4             return ServerResponse.createByErrorMessage("参数错误,token需要传递");
     5         }
     6         //校验用户名是否存在
     7         ServerResponse validResponse = this.checkValid(username, Const.USERNAME);
     8         if(validResponse.isSuccess()) {
     9             //用户不存在
    10             return ServerResponse.createByErrorMessage("用户不存在");
    11         }
    12         //从cache中获取token,根据key拿到value值
    13     //    String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX + username);
    14 
    15         String token = RedisShardedPoolUtil.get(Const.TOKEN_PREFIX + username);
    16 
    17         //校验cache中的token是否有效
    18         if(StringUtils.isBlank(token)) {
    19             return ServerResponse.createByErrorMessage("token无效或者过期");
    20         }
    21         //校验传入的forgetToken和token是否相同
    22         //这里用stringUtils可以避免string.equals中string出现null的问题,即使这里传入null也是可以接受的,不会报错
    23         if(StringUtils.equals(forgetToken, token)) {
    24             //将新输入的密码进行md5加密后再更新到数据库中
    25             String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
    26             int rowCount = userMapper.updatePasswordByUsername(username, md5Password);
    27             if(rowCount > 0) {
    28                 return ServerResponse.createBySuccessMessage("修改密码成功");
    29             }
    30         }
    31         else {
    32             return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token");
    33         }
    34         return ServerResponse.createByErrorMessage("修改密码失败");
    35     }
    View Code

    5.获取用户信息

    controller层实现:

    先从cookie中获取是否登录信息,然后拿到这个sessionId后,去redis中根据这个sessionId,拿到user对象,根据userId从数据库中获取到具体的用户信息,返回给前端。

     1     @RequestMapping(value = "get_information.do", method = RequestMethod.POST)
     2     @ResponseBody
     3     public ServerResponse<User> getInformation(HttpServletRequest request) {
     4 
     5         String loginToken = CookieUtil.readLoginToken(request);
     6         if(StringUtils.isEmpty(loginToken)) {
     7             return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
     8         }
     9         String userJsonStr = RedisShardedPoolUtil.get(loginToken);
    10         User currentUser = JsonUtil.string2Obj(userJsonStr, User.class);
    11 
    12         if(currentUser == null) {
    13             return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "未登录,需要强制登录status=10");
    14         }
    15         return iUserService.getInformation(currentUser.getId());
    16     }
    View Code

    6.更新用户信息

    7.退出登录

    掌握:

    1.横向越权、纵向越权安全漏洞

    2.MD5明文加密及增加salt盐值

    3.Guava缓存的使用

    4.高复用服务响应对象的设计思想及抽象封装

     1 /**
     2  * Created by cq on 2017/10/31.
     3  */
     4 @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
     5 //保证序列化json的时候,如果是null的对象,key也会消失
     6 //比如在创建失败的时候,只需要将status和msg显示出来,但是如果不加上面的注解会将data也显示出来,其值会显示null
     7 public class ServerResponse<T> implements Serializable{
     8 
     9     private int status;
    10     private String msg;
    11     private T data;
    12 
    13     private ServerResponse(int status) {
    14         this.status = status;
    15     }
    16     //如果第二个参数不是string类型调用下面这个构造器
    17     private ServerResponse(int status, T data) {
    18         this.status = status;
    19         this.data = data;
    20     }
    21     //如果第二个参数是string类型调用下面这个构造器
    22     private ServerResponse(int status, String msg) {
    23         this.status = status;
    24         this.msg = msg;
    25     }
    26     private ServerResponse(int status, String msg, T data) {
    27         this.status = status;
    28         this.msg = msg;
    29         this.data = data;
    30     }
    31 
    32     @JsonIgnore
    33     //使之不在json序列化结果当中
    34     //判断响应是否成功
    35     public boolean isSuccess() {
    36         return this.status == ResponseCode.SUCCESS.getCode();
    37     }
    38 
    39     //下面三个get开头的public方法在json序列化时都会显示出来供前端看到
    40     //数据格式显示也就如下:
    41     /*
    42     * {status:xxx,
    43     * msg:xx,
    44     * data:xxx}
    45     * */
    46     public int getStatus() {
    47         return status;
    48     }
    49 
    50     public T getData() {
    51         return data;
    52     }
    53 
    54     public String getMsg() {
    55         return msg;
    56     }
    57 
    58     //成功
    59     //返回值是泛型<T>,传入0表示创建是成功的
    60     public static <T> ServerResponse<T> createBySuccess() {
    61         return new ServerResponse<T>(ResponseCode.SUCCESS.getCode());
    62     }
    63 
    64     //创建成功传入一个msg再返回
    65     public static <T> ServerResponse<T> createBySuccessMessage(String msg) {
    66         return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg);
    67     }
    68 
    69     //创建成功传入data再返回
    70     public static <T> ServerResponse<T> createBySuccess(T data) {
    71         return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), data);
    72     }
    73 
    74     //如果参数是string类型,但是应该把其赋给data而不是msg该怎么做?
    75     //调用下面的public方法同时传入msg和data即可
    76     //创建成功传入一个msg和data再返回
    77     public static <T> ServerResponse<T> createBySuccess(String msg, T data) {
    78         return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg, data);
    79     }
    80 
    81     //失败
    82     public static <T> ServerResponse<T> createByError() {
    83         return new ServerResponse<T>(ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDesc());
    84     }
    85 
    86     //创建失败传入一个错误提示信息errorMessage
    87     public static <T> ServerResponse<T> createByErrorMessage(String errorMessage) {
    88         return new ServerResponse<T>(ResponseCode.ERROR.getCode(), errorMessage);
    89     }
    90 
    91     //创建失败手动传入一个code和errorMessage
    92     public static <T> ServerResponse<T> createByErrorCodeMessage(int errorCode, String errorMessage) {
    93         return new ServerResponse<T>(errorCode, errorMessage);
    94     }
    95 
    96 }
    View Code

    5.session的使用

    6.json注解使用

  • 相关阅读:
    实例变量和类变量
    Spring源码解读(一)
    linux shell学习三
    linux shell学习二
    linux shell学习一
    利用Zynq Soc创建一个嵌入式工程
    (转) 使用vivado创建工程 4[完结]
    (转) 使用vivado创建工程 3
    (转) 使用vivado创建工程 2
    (转) 使用vivado创建工程 1
  • 原文地址:https://www.cnblogs.com/cing/p/7806324.html
Copyright © 2020-2023  润新知