美文网首页我爱编程
Web认证相关总结

Web认证相关总结

作者: 智明书 | 来源:发表于2018-03-28 18:52 被阅读86次

​ 总结在Web开发中跟认证相关的流程,该案例使用Node.js托管前端页面,实现到后端服务器的路由跳转,称为UI Service;业务相关的请求放在Query Service中;认证相关的请求(比如登录、登出、更改密码、Token认证等)放在Auth Service中。

认证相关的数据库设计

account表

create table account
(
   id                   char(32) not null,
   account_access_info_id char(32),
   company_id           char(32),
   firstname            varchar(32) not null,
   lastname             varchar(32) not null,
   email                varchar(32) not null,
   phone_number         varchar(32),
   title                varchar(32),
   password             varchar(200),
   salt                 varchar(200),
   reset_password_token varchar(200),
   reset_password_token_expire timestamp,
   is_active            bool not null,
   last_update_time     timestamp,
   update_count         int,
   primary key (id)
);

account_access_info表

create table account_access_info
(
   id                   char(32) not null,
   account_id           char(32),
   login_token          varchar(200),
   login_token_expire   timestamp,
   attempts             int,
   last_attempts_time   timestamp,
   is_locked            bool not null,
   primary key (id)
);

登录认证

前端认证

​ 登录过程首先要前端做一遍认证,用于拦截掉普通用户输入错误的情况,比如邮箱格式,密码格式(8-15位并且必须有大小写字母和数字)

  • 初始状态,登录按钮处于disable状态,鼠标无法点击,即无法提交POST请求
  • 用户输入帐号,输入完毕后通过TAB键或ENTER键(利用onKeyDown事件监听enter按钮)切换光标到密码输入框;同时检测用户输入的帐号是否符合邮箱格式,如不符合,提示Please input a valid email address
  • 用户输入密码,一旦用户输入了第一位密码同时邮箱格式正确,令LOGIN按钮enable。当用户输入完毕,通过点击LOGIN按钮或按下Enter(利用onKeyDown事件监听enter按钮)来提交POST请求。POST请求的格式可以做如下参考:
// 在发送POST请求的时候给页面填加遮罩,防止用户有其他操作
$('#page_loading').removeClass('hidden');   

$.ajax({
      url: path.LOGIN,
      method: 'POST',
      dataType: 'json',
      contentType: 'application/json; charset=utf-8',
      data: JSON.stringify({
        username: _state.userName,
        password: _state.password,
      }),
      success: function (response) {
        // 请求结束,去掉遮罩
        $('#page_loading').addClass('hidden');
        // 保存token等信息
        let responseJSON;
        if (typeof response === 'string') {
          responseJSON = JSON.parse(response);
        } else {
          responseJSON = response;
        }
        if (responseJSON.token.length > 0) {
          sessionStorage.__ecs_user_token = responseJSON.token; // 保存token
        }
        // 页面跳转
        location.href = `${path.MAIN_PAGE}?token=${responseJSON.token}`;
      },
      error: function(jqXHR, textStatus) {
        // 请求结束,去掉遮罩
        $('#page_loading').addClass('hidden');
        ...
      }
 })

待登录请求成功后,前端使用location.href跳转到首页,请求中要携带token

后端的登录认证

格式验证

​ 虽然前端已经做过一次帐号、密码的验证,但服务端必须做再次的确认,因为前端页面验证不能防范其他人恶意的尝试密码。记住:对所有到达后端的请求都要保持怀疑的态度

if (!Validators.validateEmailAddress(loginRequestModel.getUsername()) || !Validators.validatePassword(loginRequestModel.getPassword())) {
    logger.info("/login: Invalid username or password");
     map.put("success", false);
     map.put("message", "Invalid username or password");
     return new ResponseEntity<Map<String, Object>>(map, HttpStatus.BAD_REQUEST);
}

数据库验证

  • 验证用户输入的username是否在account表中
  • 通过id查看account_access_info表中该用户帐号是否被锁住(isLocked字段)
  • 通过PasswordUtil.checkPassword工具验证密码,参数为account表中的salt, password和用户输入的密码
  • 如果输入错误,将account_access_info表中的attempts字段加1,并提示剩余的尝试次数;如果5次输入错误,提示账户被锁,需要联系管理员解锁密码
  • 通过JwtUtil.generateToken工具生成token,payload中的字段依业务逻辑而定,可以添加iat, exp, accountType等信息
  • 用户认证成功,生成http响应体,参考如下
@AllArgsConstructor
@NoArgsConstructor
public @Data class LoginResponseModel {
    private Boolean success;
    private String message;
    private String token;
    private String firstName;
    private String lastName;
    private String title;
    private String companyID;
}

前端响应

前端基于Ajax的请求结果做不同的展现:

  • 超时,Connection timeout. Please try again
  • 200,保存后端返回的信息,如token,用户信息等
  • 400,Invalid username or password. Please try again or use Forget Password link below.
  • 401,Invalid username or password. Please try again or use Forget Password link below.
  • 423,Your account is locked due to too many times failure.
  • 500,Server error. Please try again.

注:登录认证过程永远不要告诉用户到底是用户名错误还是密码错误。只需要给出大概的提示:Invalid username or password。这可以防止攻击者在不知道密码的情况下,遍历出有效的用户名。


登出认证

登出时前端发送一个/logoutGET请求,只需要在http请求头的x-access-token中添加token,不需要额外添加用户信息,因为在token的payload中已经携带了accoutID信息。

headers: {
    'x-access-token': sessionStorage.token,
}

后端首先要解析token,确保token未篡改, 并在有效期间内

从token的payload中获取accoutID,并在account_access_info表中查找,如果找不到用户,则返回401User attempts to logout an account with no access information in the database

判断是移动端还是web端发送的请求,然后将相应的token删除,并返回200


忘记密码认证

​ 在前端的登录页面有Forget password的按钮,当用户忘记密码,通过POST /passport/forgotpassword请求并携带用户名


后端首先验证用户名Validators.validateEmailAddress(要永远对前端的请求保持怀疑态度)

从account表查找用户名,如果不存在,返回400 Invalid username

生成resetpasswordtokenreset_password_token_expire,过期时间可以设定为2小时内有效,更新数据库

生成邮件,邮件内有url,用户名字等信息

返回200


用户的邮箱会收到一封邮件,提示重置密码:

<p>
  You recently requested a password reset for your ECS Monitoring System account. Please click on the below link to continue resetting your password.
</p>
<p>
  <a href="${resetpassword}">Reset Your Password &gt;</a>
</p>

接着会执行重置密码的认证


重置密码认证

​ 有两种情况会执行重置密码的认证:一是用户忘记密码, 执行忘记密码的认证之后,用户会收到重置密码的邮件;二是管理员在后台管理界面新增加一个用户,该用户会收到一封创建帐号的邮件。不论是上述哪种情况,在邮件中会有一个/resetpassword/{token}的URL,用于跳转到重置密码的界面。


后端收到/resetpassword/{token}的GET请求后,验证token是否为空,否则返回400 Missing token

account表中查找resetpasswordtoken,如果没有,返回400,Invalid token。如果有,返回200

UI服务器接收到Auth服务器的200响应后,将重置密码页面展示给用户:

router.get('/resetpassword/:token', (req, res) => {
  authenticationMiddleware.validateResetPageToken(req, res, (reqNext, resNext) => {
    resNext.status(200).set('Content-Type', 'text/html')
      .sendFile(path.join(__dirname, '../public/resetpassword.html'));
  });
});

在重置密码页面,用户POST/resetpassword/{token}请求,请求体中携带password, confirmPassword

后端验证token, password, confirmPassword是否为空,否则返回400 Missing required filed

验证password, confirmPassword是否相等,否则返回400 Password doesn't match with confirm password

验证密码是否有效Validators.validatePassword,否则返回400 Password must be 8-16 characters with at least one uppercase character, one lowercase character, one number and one special character

通过resetpasswordtoken查account表,验证是否有有效用户,否则返回400

通过account表的resetPasswordTokenExpire字段验证当前token是否过期(重置密码2个小时之内有效)

通过PasswordUtil.encryptPassword通过生成salthashpassword

修改account表并保存,注:应该删除resetPasswordToken, resetPasswordTokenExpire字段

accountEntity.setSalt(passwordEncryptionResponseModel.getSalt());
accountEntity.setPassword(passwordEncryptionResponseModel.getHashPassword());
// resetPasswordToken and resetPasswordTokenExpire will be useless. So remove them
accountEntity.setResetPasswordToken(null);
accountEntity.setResetPasswordTokenExpire(null);
accountEntity.setUpdateCount(accountEntity.getUpdateCount() + 1);
accountEntity.setLastUpdateDateTime(now);
accountRepository.save(accountEntity);

返回200,并给用户发送一封邮件通知密码已经重置成功

<p>Dear ${firstname} ${lastname}</p>
<p>You recently changed your password for xxx System.</p>
<p>If you didn't make this password change or if you believe unauthorized person has accessed your account, please go to <a href="xxx.xxx.com">Forgot Password</a> to reset your password immediately.</p>

更改密码认证

  • 验证password, confirmPassword是否相同
  • 验证currentPassword, password是否相同
  • Validators.validatePassword验证currentPassword, password, confirmPassword是否是有效的密码格式
  • 通过JwtUtil.parseToken(token)验证token,并解析出accountID
  • 使用accountID从account表中获取用户信息
  • PasswordUtil.checkPassword(currentPassword, accountEntity.getSalt(), accountEntity.getPassword())),验证currentPassword是否正确
  • 确认当前密码输入正确后,使用PasswordUtil.encryptPassword(password)新密码生成salthashPassword
  • 在account表中更新当前用户的信息:
accountEntity.setSalt(passwordEncryptionResponseModel.getSalt());
accountEntity.setPassword(passwordEncryptionResponseModel.getHashPassword());
accountEntity.setUpdateCount(accountEntity.getUpdateCount() + 1);
accountEntity.setLastUpdateDateTime(now);
accountRepository.save(accountEntity);
  • 请求成功,返回200

Token认证

​ 使用RESTful API向服务端发送请求的时候,需要对请求资源的用户进行身份认证。具体实现为:

用户发起的请求的请求先经过基于Node.js的ui-service,然后先路由到/passport/verifymobiletoken接口进行token验证

router.get('/reports', (req, res) => {
  authenticationMiddleware.validateCommonAccessToken(req, res, (reqNext, resNext, body) => {
    forwardMiddleware.forwardQueryRequest(config.server.query, reqNext, resNext, body);
  });
});

认证服务器首先对token进行验证和解析,获取payload中的accountID

在account表中查找是否用户存在

在其他表中查找跟用户有关的信息(该信息是RESTful请求需要的信息)

返回200

ui-service接受到auth服务器的200响应后,将请求转发到query服务器。否则认证失败,将页面定向到登录页面

if (token) {
    const postOpts = {
      url: isMobile ? config.servicePath.verifymobiletoken : config.servicePath.verifywebtoken,
      method: 'POST',
      rejectUnauthorized: false,
      headers: { 'Content-Type': 'application/json' },
      json: { token },
    };
    request.post(postOpts, (err, httpResponse, body) => {
      ...
      return next(req, res, body);
    });
} else {
    return res.redirect('/passport/login');
}

Web端和IOS端的认证

​ 由于IOS和Web分别使用各自的token进行认证, 而两者在认证的业务逻辑上没有任何区别,因此可以在公用一套代码逻辑,以Token认证过程为例:

@PostMapping(value = {"/verifywebtoken","/verifymobiletoken"})
    public ResponseEntity<Map<String,Object>> handleVerifyToken(
            HttpServletRequest httpRequest,
            @RequestBody TokenRequestModel tokenRequestModel) throws FileNotFoundException{
    // distinguish request from web portal or mobile app
    final String requestMapping = (String) httpRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
    final boolean isMobile = requestMapping.contains("/verifymobiletoken");
 
      ...
        
    return authenticationService.handleVerifyToken(token,isMobile); 
}

相关文章

  • Web认证相关总结

    ​ 总结在Web开发中跟认证相关的流程,该案例使用Node.js托管前端页面,实现到后端服务器的路由跳转,称为...

  • 基于Token的WEB后台认证机制

    相关文章: 1.基于Token的WEB后台认证机制 http://www.cnblogs.com/xiekeli/...

  • 直播产品主播认证流程分析

    主播认证流程 一、全民直播(认证流程+文案优化) 分析总结: 整个认证过程符合国家出台行法规相关规定,主播必须进行...

  • 快速理解JWT(JWS/JWE)认证并在Python中实现

    JWT,即Json Web Token认证机制,常用于web会话认证,对比传统的Session认证而言,它的优势很...

  • HTTP 概述

    HTTP 概述 本文为HTTP Web基础部分,概要总结下HTTP;Web浏览器、服务器和相关的Web应用程序都是...

  • 身份验证

    目前比较成熟的Web服务认证方式有HTTP认证、自定义认证、采用现有工具包。利用Web服务可以建立面向服务的架构(...

  • web认证

    关于我正在做的路由器的web认证方式是这样的: 客户端首先向服务器发送一条不带认证的get。 服务器返回 Auth...

  • oidc oauth2 相关

    认证相关

  • 思科ISE 对公司访客进行Portal 认证(基于HTTPS 协

    Portal 认证简介 Portal认证通常也称为Web认证,用户接入网络时,必须在门户网站进行认证,如果未认证成...

  • 目录索引

    开发总结1、Java · 后端开发相关总结2、Web应用系统设计开发经验总结3、常规问题定位不完全手册 系统设计1...

网友评论

    本文标题:Web认证相关总结

    本文链接:https://www.haomeiwen.com/subject/fcpucftx.html