乐优商城(三十一)——授权中心

目录

三、首页判断登录状态

3.1 页面代码

3.2 后台实现校验用户接口

3.3 测试

3.4 刷新token

四、网关的登录拦截

4.1 引入jwt相关配置

4.2 编写过滤逻辑

4.3 白名单


三、首页判断登录状态

虽然cookie已经成功写入,但是首页的顶部,登录状态依然没能判断出用户信息:

这里需要向后台发起请求,根据cookie获取当前用户的信息。

3.1 页面代码

页面的顶部已经封装为一个独立的Vue组件,在/js/pages/shortcut.js

在created函数中,查询用户信息:

后台:

请求已经发出,因为token在cookie中,因此本次请求肯定会携带token信息在头中。

3.2 后台实现校验用户接口

leyou-authentication-service中定义用户的校验接口,通过cookie获取token,然后校验通过返回用户信息。

  • 请求方式:GET

  • 请求路径:/verify

  • 请求参数:无,但需要从cookie中获取token信息

  • 返回结果:UserInfo,校验成功返回用户信息;校验失败,则返回401

代码:

   /**
     * 用户验证
     * @param token
     * @return
     */
    @GetMapping("verify")
    public ResponseEntity<UserInfo> verifyUser(@CookieValue("LY_TOKEN") String token){
        try{
            //1.从token中解析token信息
            UserInfo userInfo = JwtUtils.getInfoFromToken(token,this.properties.getPublicKey());
            //2.解析成功返回用户信息
            return ResponseEntity.ok(userInfo);
        }catch (Exception e){
            e.printStackTrace();
        }
        //3.出现异常,相应401
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

getInfoFromToken代码:

    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     * @throws Exception
     */
    public static UserInfo getInfoFromToken(String token, PublicKey publicKey) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        return new UserInfo(
                ObjectUtils.toLong(body.get(JwtConstans.JWT_KEY_ID)),
                ObjectUtils.toString(body.get(JwtConstans.JWT_KEY_USER_NAME))
        );
    }

3.3 测试

页面效果:

3.4 刷新token

每当用户在页面进行新的操作,都应该刷新token的过期时间,否则30分钟后用户的登录信息就无效了。而刷新其实就是重新生成一份token,然后写入cookie即可。

那么问题来了:怎么知道用户有操作呢?

事实上,每当用户来查询其个人信息,就证明他正在浏览网页,此时刷新cookie是比较合适的时机。因此可以对校验用户登录状态的接口进行改进,加入刷新token的逻辑。

    /**
     * 用户验证
     * @param token
     * @return
     */
    @GetMapping("verify")
    public ResponseEntity<UserInfo> verifyUser(@CookieValue("LY_TOKEN") String token,HttpServletRequest request,
                                               HttpServletResponse response){
        try{
            //1.从token中解析token信息
            UserInfo userInfo = JwtUtils.getInfoFromToken(token,this.properties.getPublicKey());
            //2.解析成功要重新刷新token
            token = JwtUtils.generateToken(userInfo,this.properties.getPrivateKey(),this.properties.getExpire());
            //3.更新Cookie中的token
            CookieUtils.setCookie(request,response,this.properties.getCookieName(),token,this.properties.getCookieMaxAge());
            //4.解析成功返回用户信息
            return ResponseEntity.ok(userInfo);
        }catch (Exception e){
            e.printStackTrace();
        }
        //5.出现异常,相应401
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

四、网关的登录拦截

在Zuul编写拦截器,对用户的token进行校验,如果发现未登录,则进行拦截。

4.1 引入jwt相关配置

既然是登录拦截,一定是前置拦截器,在leyou-gateway中定义。

首先在pom.xml中,引入所需要的依赖:

<dependency>
    <groupId>com.leyou.common</groupId>
    <artifactId>leyou-common</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>com.leyou.auth</groupId>
    <artifactId>leyou-auth-common</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

然后编写application.yml,添加如下内容:

leyou:
  jwt:
    pubKeyPath:  C:\\tmp\\rsa\\rsa.pub # 公钥地址
    cookieName: LY_TOKEN # cookie的名称

4.2 编写过滤逻辑

基本逻辑:

  • 获取cookie中的token

  • 通过JWT对token进行校验

  • 通过:则放行;不通过:则重定向到登录页

代码:

package com.leyou.filter;

import com.leyou.auth.utils.JwtUtils;
import com.leyou.config.JwtProperties;
import com.leyou.utils.CookieUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author: 98050
 * @Time: 2018-10-24 16:21
 * @Feature: 登录拦截器
 */
@Component
@EnableConfigurationProperties(JwtProperties.class)
public class LoginFilter extends ZuulFilter {

    @Autowired
    private JwtProperties properties;

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 5;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        //1.获取上下文
        RequestContext context = RequestContext.getCurrentContext();
        //2.获取request
        HttpServletRequest request = context.getRequest();
        //3.获取token
        String token = CookieUtils.getCookieValue(request,this.properties.getCookieName());
        //4.校验
        try{
            //4.1 校验通过,放行
            JwtUtils.getInfoFromToken(token,this.properties.getPublicKey());
        }catch (Exception e){
            //4.2 校验不通过,返回403
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
        }
        return null;
    }
}

重启,刷新页面,发现请求校验的接口也被拦截了:

证明拦截器生效了,但是,这个路径是不应该被拦截,需要白名单。

4.3 白名单

要注意,并不是所有的路径我们都需要拦截,例如:

  • 登录校验接口:/auth/**

  • 注册接口:/user/register

  • 数据校验接口:/user/check/**

  • 发送验证码接口:/user/code

  • 搜索接口:/search/**

另外,跟后台管理相关的接口,因为没有做登录和权限,因此暂时都放行,但是生产环境中要做登录校验:

  • 后台商品服务:/item/**

所以,需要在拦截时,配置一个白名单,如果在名单内,则不进行拦截。

application.yaml中添加规则:

leyou:
  filter:
    allowPaths:
      - /api/auth
      - /api/search
      - /api/user/register
      - /api/user/check
      - /api/user/code
      - /api/item

然后读取这些属性:

package com.leyou.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * @Author: 98050
 * @Time: 2018-10-24 16:55
 * @Feature: 过滤白名单
 */
@ConfigurationProperties(prefix = "leyou.filter")
public class FilterProperties {

    private List<String> allowPaths;

    public List<String> getAllowPaths() {
        return allowPaths;
    }

    public void setAllowPaths(List<String> allowPaths) {
        this.allowPaths = allowPaths;
    }
}

在过滤器中的shouldFilter方法中添加判断逻辑:

    @Override
    public boolean shouldFilter() {
        //1.获取上下文
        RequestContext context = RequestContext.getCurrentContext();
        //2.获取request
        HttpServletRequest request = context.getRequest();
        //3.获取路径
        String requestUri = request.getRequestURI();
        logger.info(requestUri);
        //4.判断白名单
        return !isAllowPath(requestUri);
    }

    private boolean isAllowPath(String requestUri) {
        //1.定义一个标记
        boolean flag = false;

        //2.遍历允许访问的路径
        for (String path : this.filterProperties.getAllowPaths()){
            if (requestUri.startsWith(path)){
                flag = true;
                break;
            }
        }
        return flag;
    }

知识点:

request.getRequestURL() 返回全路径

request.getRequestURI() 返回除去host(域名或者ip)部分的路径

request.getContextPath() 返回工程名部分,如果工程映射为/,此处返回则为空

request.getServletPath() 返回除去host和工程名部分的路径

例如:
request.getRequestURL() :http://localhost:8080/jqueryLearn/resources/request.jsp 
request.getRequestURI(): /jqueryLearn/resources/request.jsp
request.getContextPath():/jqueryLearn 
request.getServletPath():/resources/request.j

刷新页面:

五、退出

删除cookie中的token即可。

logout() {
    // 删除cookie中的token即可
    Cookies.remove("LY_TOKEN",{
        path:"/",
        domain:"leyou.com"
    });
    window.location = 'http://www.leyou.com'
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值