19.JWT

1►JWT博客推荐

阮老师讲得很好了,网址如下:

http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

2►ry是怎么践行JWT的呢?

问题一:不登录的时候有token吗?

答:没有,所以只能在login页面,凡是想跳转其他界面,都被重定向到登录,硬生生让你登录。前端阻拦的代码如下:

问题二:token什么时候生成的?

答:登录的时候生成的,具体代码讲述:

 public String login(String username, String password, String code, String uuid)
{
        boolean captchaOnOff = configService.selectCaptchaOnOff();
        // 验证码开关
        if (captchaOnOff)
        {
            validateCaptcha(username, code, uuid);
        }
        // 用户验证
        Authentication authentication = null;
        try
        {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }

最后一句话,他说生成token,于是他执行:

 public String createToken(LoginUser loginUser)
{
        String token = IdUtils.fastUUID();
        loginUser.setToken(token);
        setUserAgent(loginUser);
        refreshToken(loginUser);

        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.LOGIN_USER_KEY, token);
        return createToken(claims);
    }

然后它又是最后一个话在生成token,好家伙,玩我是吧?点进去我们才看到真的生成方法:


    private String createToken(Map<String, Object> claims)
{
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, secret).compact();
        return token;
    }

现在token生成好了,大家要注意,refreshToken方法已经把当前成功登录的人的信息存到了redis中,前缀是login_tokens: + 当前的tokenId,tokenId是一个uuid。

问题三,用户登录后,发请求是怎么自动带上token的?

登录成功的时候,前端存了一份token在cookie中,登录代码如下:

// 登录
    Login({ commit }, userInfo) {
      const username = userInfo.username.trim()
      const password = userInfo.password
      const code = userInfo.code
      const uuid = userInfo.uuid
      return new Promise((resolve, reject) => {
        login(username, password, code, uuid).then(res => {
          setToken(res.token)
          commit('SET_TOKEN', res.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

引入眼帘有一个setToken,里面就将token放cookie,代码如下:


export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

接下来如果要发请求,request.js会自动带上,如下代码:

可以看到,它会去config.headers看看到底要不要,如果我们在请求头指定了不要,那么发请求就不会带上token,否则就会被带上token。

问题四:我再次请求的时候带上了token,后端在哪问我带没带token呢?


package com.ruoyi.framework.security.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;

/**
 * token过滤器 验证token有效性
 * 
 * @author ruoyi
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
    @Autowired
    private TokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException
{
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
        {
            tokenService.verifyToken(loginUser);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}

getLoginUser方法总是在试图拿到token。然后验证token是否正确,token有没有过期,然后把用户该有的权限重新设置在上下文中。

该拦截器是在哪里设置的呢?

   @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
{
        // 注解标记允许匿名访问的url
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
        permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());

        httpSecurity
                // CSRF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                .antMatchers("/login", "/register", "/captchaImage").anonymous()
                // 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable();
        // 添加Logout filter
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
    }

相关推荐

  1. <span style='color:red;'>19</span>.<span style='color:red;'>JWT</span>

    19.JWT

    2024-07-10 17:24:04      11 阅读
  2. <span style='color:red;'>JWT</span>详解

    JWT详解

    2024-07-10 17:24:04      32 阅读
  3. JWT详解

    2024-07-10 17:24:04       41 阅读
  4. <span style='color:red;'>JWT</span>登录

    JWT登录

    2024-07-10 17:24:04      42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 17:24:04       5 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 17:24:04       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 17:24:04       4 阅读
  4. Python语言-面向对象

    2024-07-10 17:24:04       5 阅读

热门阅读

  1. 实证Stata代码命令汇总

    2024-07-10 17:24:04       10 阅读
  2. 将 build.gradle 配置从 Groovy 迁移到 Kotlin

    2024-07-10 17:24:04       11 阅读
  3. MySQL数据库字符集utf8mb4的排序规则介绍

    2024-07-10 17:24:04       9 阅读
  4. 人形机器人强化学习控制分类

    2024-07-10 17:24:04       10 阅读
  5. 小抄 20240708

    2024-07-10 17:24:04       8 阅读
  6. sklearn基础教程

    2024-07-10 17:24:04       12 阅读
  7. 图形渲染基础-GPU驱动的渲染管线

    2024-07-10 17:24:04       11 阅读
  8. 数据库的基本概念

    2024-07-10 17:24:04       11 阅读
  9. 图形渲染基础-Unity渲染管线介绍

    2024-07-10 17:24:04       12 阅读
  10. spring xml实现bean对象(仅供自己参考)

    2024-07-10 17:24:04       10 阅读
  11. Tomcat异常处理【Spring源码学习】

    2024-07-10 17:24:04       14 阅读