尚品汇总结五:商品详情模块(面试专用)

一、登录业务介绍

早期单一服务器,用户认证

尚品汇总结五:商品详情模块(面试专用)_第1张图片

缺点:单点性能压力,无法扩展

WEB应用集群,session共享模式

Tomcat广播session

尚品汇总结五:商品详情模块(面试专用)_第2张图片

分布式,SSO(single sign on)模式

尚品汇总结五:商品详情模块(面试专用)_第3张图片

业务流程图

尚品汇总结五:商品详情模块(面试专用)_第4张图片

二、认证中心模块

数据库表:user_info!密码应该是加密的!

在设计密码加密方式时 一般是使用MD5+盐的方式进行加密和解密

1.登录业务流程

 密码:要求用户在注册的时候 多种组合.

 要求  大写 小写字母+数字+特殊字符  必须超过8位.

尚品汇总结五:商品详情模块(面试专用)_第5张图片

2、业务实现

Web-all工程

package com.atguigu.gmall.all.controller;

/**

 * 

 * 用户认证接口  *

 *  */ @Controller @RequestMapping public class PassportController {     @GetMapping("login.html")     public String login(HttpServletRequest request) {         String originUrl = request.getParameter("originUrl");         request.setAttribute("originUrl",originUrl);         return "login";     } }

认证中心模块service-user

package com.atguigu.gmall.user.controller;

  /**

 * 

 * 用户认证接口  *

 */ @RestController @RequestMapping("/api/user/passport") public class PassportController {     @Autowired     private UserService userService;     @Autowired     private RedisTemplate redisTemplate;     @PostMapping("login")     public Result login(@RequestBody UserInfo userInfo, HttpServletRequest request, HttpServletResponse response) {         System.out.println("进入控制器!");         UserInfo info = userService.login(userInfo);         if (info != null) {             String token = UUID.randomUUID().toString().replaceAll("-", "");             HashMap map = new HashMap<>();             map.put("name", info.getName());             map.put("nickName", info.getNickName());             map.put("token", token);             redisTemplate.opsForValue().set(RedisConst.USER_LOGIN_KEY_PREFIX + token, info.getId().toString(), RedisConst.USERKEY_TIMEOUT, TimeUnit.SECONDS);             return Result.ok(map);         } else {             return Result.fail().message("用户名或密码错误");         }     }

package com.atguigu.gmall.user.service.impl;

  @Service

  public class UserServiceImpl implements UserService {

    // 调用mapper 层

    @Autowired

    private UserInfoMapper userInfoMapper;

    @Override

    public UserInfo login(UserInfo userInfo) {

        // select * from userInfo where userName = ? and passwd = ?

        // 注意密码是加密:

        String passwd = userInfo.getPasswd(); //123

        // 将passwd 进行加密

        String newPasswd = DigestUtils.md5DigestAsHex(passwd.getBytes());

        QueryWrapper queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("login_name", userInfo.getLoginName());

        queryWrapper.eq("passwd", newPasswd);

        UserInfo info = userInfoMapper.selectOne(queryWrapper);

        if (info != null) {

            return info;

        }

        return null;

    }

}

三、用户认证与服务网关整合

1、业务流程

  1. 所有请求都会经过服务网关,服务网关对外暴露服务,不管是api异步请求还是web同请求都走网关,在网关进行统一用户认证
  2. 既然要在网关进行用户认证,网关得知道对哪些url进行认证,所以我们得对url制定规则
  3. Web页面同请求(如:*.html),我采取配置白名单的形式,凡是配置在白名单里面的请求都是需要用户认证的(注:也可以采取域名的形式,方式多多)
  4. Api接口异步请求的,我们采取url规则匹配,如:/api/**/auth/**,如凡是满足该规则的都必须用户认证

网关全局过滤器做了什么事???

请求过滤,过滤到用户的请求,统一鉴权,鉴别有没有访问权限.

用户登录的认证,getUserId(),根据token去redis中查用户id.返回用户id之前 还有判断IP是否一致,当前访问的ip和登录时的ip比对,如果不一致,说明用户的环境发生变化了,让他去登录.

尚品汇总结五:商品详情模块(面试专用)_第6张图片

 

2、业务实现

/**

 * 

 * 全局Filter,统一处理会员登录与外部不允许访问的服务  *

 *  */ @Component public class AuthGlobalFilter implements GlobalFilter, Ordered {     @Autowired     private RedisTemplate redisTemplate;     private AntPathMatcher antPathMatcher = new AntPathMatcher();     //web服务配置必须登录的url     private static String[] authUrls = {"trade.html","myOrder.html","list.html"};     @Override     public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {         ServerHttpRequest request = exchange.getRequest();         String path = request.getURI().getPath();         //内部服务接口,不允许外部访问         if(antPathMatcher.match("/**/inner/**", path)) {             ServerHttpResponse response = exchange.getResponse();             return out(response);         }         String userId = this.getUserId(request);         //api接口,异步请求,校验用户必须登录         if(antPathMatcher.match("/api/**/auth/**", path)) {             if(StringUtils.isEmpty(userId)) {                 ServerHttpResponse response = exchange.getResponse();                 return out(response);             }         }         // web服务,同步请求,校验用户必须登录         for(String url : authUrls) {             if(path.indexOf(url) != -1 && StringUtils.isEmpty(userId)) {                 ServerHttpResponse response = exchange.getResponse();                 //303状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源                 response.setStatusCode(HttpStatus.SEE_OTHER);                 response.getHeaders().set(HttpHeaders.LOCATION, "http://www.gmall.com/login.html?originUrl="+request.getURI());                 return response.setComplete();             }         }         //设置网关请求头         String userTempId = this.getUserTempId(request);         if(!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)) {             if(!StringUtils.isEmpty(userId)) {                 request.mutate().header("userId", userId).build();             }             if(!StringUtils.isEmpty(userTempId)) {                 request.mutate().header("userTempId", userTempId).build();             }             //将现在的request 变成 exchange对象             return chain.filter(exchange.mutate().request(request).build());         }         return chain.filter(exchange);     }     @Override     public int getOrder() {         return 0;     }     /**      * api接口鉴权失败返回数据      * @param response      * @return      */     private Mono out(ServerHttpResponse response) {         Result result = Result.build(null, ResultCodeEnum.LOGIN_AUTH);         byte[] bits = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);         DataBuffer buffer = response.bufferFactory().wrap(bits);         //指定编码,否则在浏览器中会中文乱码         response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");         return response.writeWith(Mono.just(buffer));     }     /**      * 获取当前登录用户id      * @param request      * @return      */     private String getUserId(ServerHttpRequest request) {         String token = "";         List tokenList = request.getHeaders().get("token");         if(null  != tokenList) {             token = tokenList.get(0);         } else {             MultiValueMap cookieMultiValueMap =  request.getCookies();             HttpCookie cookie = cookieMultiValueMap.getFirst("token");             if(cookie != null){                 token = URLDecoder.decode(cookie.getValue());             }         }         if(!StringUtils.isEmpty(token)) {             String userId = (String)redisTemplate.opsForValue().get("user:login:" + token);             return userId;         }         return "";     }     /**      * 获取当前用户临时用户id      * @param request      * @return      */     private String getUserTempId(ServerHttpRequest request) {         String userTempId = "";         List tokenList = request.getHeaders().get("userTempId");         if(null  != tokenList) {             userTempId = tokenList.get(0);         } else {             MultiValueMap cookieMultiValueMap =  request.getCookies();             HttpCookie cookie = cookieMultiValueMap.getFirst("userTempId");             if(cookie != null){                 userTempId = URLDecoder.decode(cookie.getValue());             }         }         return userTempId;     } }

3、常见问题:

  1. cookie被禁用了能登录吗?-----不能

咱们把token放到了 cookie中,禁用了 放不进去了,后续就拿不到token了.

怎么解决的? -------给用户提示:请您启用浏览器Cookie功能或更换浏览器

从后端 能获取cookie信息,如果cookie为空.

前端 向 cookie中设置值,设置不进去,给你提示!!!

     2.一顿绕

用户在A浏览器登录了  B浏览器还用登录吗?

 需要登录,不同的浏览器有不同的cookie.

PC 端登录了,  客户端还用登录吗?

也是需要的,PC 和客户端 就相当于不同的浏览器.

PC:  电脑的浏览器

客户端:手机中的 APP这种

移动端:手机中的浏览器  QQ浏览器  UC浏览器 百度浏览器

   3.用户登录信息多久过期?

分情况的.

PC端:可以设置 浏览器关闭就退出登录,前端能获取.

       Redis中有效期和 cookie中有效期都行.

   2小时   24小时  7 都行.不能设置成 1分钟  20秒这种.

客户端: 登录信息 只要用户不清除APP的数据,登录一直有效.

   4、怎么防止cookie盗用?

 登录之后的token 不是存在用户浏览器的cookie中吗,用户做什么事,电商平台是保证不了的.别人获取到了 用户浏览器cookie中的数据,拿到了这个token,把token放到他自己浏览器的cookie中,访问咱们这个电商平台,就业安全问题了.

解决:

后续访问的时候  在网关 比对ip地址了,登录时的ip和后续访问的ip比较,如果不同,说明环境发生变化了,让他重新登录。

还有让token 不能见面之意。叫什么名 只要开发人员知道就行了。还可以设置一些混淆数据。

简历:

责任描述:

负责单点登录模块功能开发,包括账号密码、手机验证码、微信扫码等功能;

 

你可能感兴趣的:(面试,面试,职场和发展)