websocket校验token:使用threadlocal存放和获取当前登录用户

2023-11-04

都知道threadlocal可以用于线程之间的变量隔离,在登录时中它可以放入当前用户,之后再用于获取当前登录用户,下面是一个使用实例。
用户实体类:(jpa框架)

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_user")
public class SysUser extends SuperEntity {
	private static final long serialVersionUID = -5886012896705137070L;

	private String username;
	private String password;
	private String nickname;
	private String headImgUrl;
	private String mobile;
	private Integer sex;
	private Boolean enabled;
	private String type;
	private String openId;
	@TableLogic
	private boolean isDel;
}

threadlocal类:

public class LoginUserContextHolder {
    private static final ThreadLocal<SysUser> CONTEXT = new TransmittableThreadLocal<>();

    public static void setUser(SysUser user) {
        CONTEXT.set(user);
    }

    public static SysUser getUser() {
        return CONTEXT.get();
    }

    public static void clear() {
        CONTEXT.remove();
    }
}

防止用户到threadlocal中:

import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class AuthUtils {
   /**
     * 校验accessToken
     */
    public static SysUser checkAccessToken(HttpServletRequest request) {
        String accessToken = extractToken(request);
        return checkAccessToken(accessToken);
    }

    public static SysUser checkAccessToken(String accessTokenValue) {
        TokenStore tokenStore = SpringUtil.getBean(TokenStore.class);
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
        if (accessToken == null || accessToken.getValue() == null) {
            throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
        } else if (accessToken.isExpired()) {
            tokenStore.removeAccessToken(accessToken);
            throw new InvalidTokenException("Access token expired: " + accessTokenValue);
        }
        OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
        if (result == null) {
            throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
        }
        return setContext(result);
    }
    /**
     * 用户信息赋值 context 对象
     */
    public static SysUser setContext(Authentication authentication) {
        SecurityContextHolder.getContext().setAuthentication(authentication);
        SysUser user = getUser(authentication);
        LoginUserContextHolder.setUser(user);
        return user;
    }

    /**
     * *从header 请求中的clientId:clientSecret
     */
    public static String[] extractClient(HttpServletRequest request) {
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith(BASIC_)) {
            throw new UnapprovedClientAuthenticationException("请求头中client信息为空");
        }
        return extractHeaderClient(header);
    }
   /**
     * 从header 请求中的clientId:clientSecret
     *
     * @param header header中的参数
     */
    public static String[] extractHeaderClient(String header) {
        byte[] base64Client = header.substring(BASIC_.length()).getBytes(StandardCharsets.UTF_8);
        byte[] decoded = Base64.getDecoder().decode(base64Client);
        String clientStr = new String(decoded, StandardCharsets.UTF_8);
        String[] clientArr = clientStr.split(":");
        if (clientArr.length != 2) {
            throw new RuntimeException("Invalid basic authentication token");
        }
        return clientArr;
    }

获取当前登录人:

    /**
     * 通过 LoginUserContextHolder 获取当前登录人
     */
    @GetMapping("/test/auth2")
    public String auth() {
        return "auth2:" + LoginUserContextHolder.getUser().getUsername();
    }

websocket鉴权:

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.websocket.server.ServerEndpointConfig;
public class WcAuthConfigurator extends ServerEndpointConfig.Configurator {
//checkOrigin:校验token
    @Override
    public boolean checkOrigin(String originHeaderValue) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        try {
            //检查token有效性
            AuthUtils.checkAccessToken(servletRequestAttributes.getRequest());
        } catch (Exception e) {
            log.error("WebSocket-auth-error", e);
            return false;
        }
        return super.checkOrigin(originHeaderValue);
    }
}

在AuthUtils.checkAccessToken方法内部最终执行了threadelocal的put方法
使用WcAuthConfigurator :
//@ServerEndpoint:
主要是将目前的类定义成一个websocket服务器端, 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端,在这里配置configurator属性为刚刚写的配置类


@Slf4j
@Component
@ServerEndpoint(value = "/websocket/test", configurator = WcAuthConfigurator.class)
public class TestWebSocketController {
    @OnOpen
    public void onOpen(Session session) throws IOException {
        session.getBasicRemote().sendText("TestWebSocketController-ok");
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

websocket校验token:使用threadlocal存放和获取当前登录用户 的相关文章

  • 如何在Spring Boot中初始化一次MongoClient并使用它的方法?

    您好 我正在尝试导出MongoClient在 Spring Boot 中成功连接后 我尝试在其他文件中使用它 这样我就不必每次需要在 MongoDB 数据库中进行更改时都调用该连接 连接非常简单 但目标是将应用程序连接到我的数据库一次 然后
  • 全静态方法和应用单例模式有什么区别?

    我正在创建一个数据库来存储有关我的网站用户的信息 我正在使用 stuts2 因此使用 Java EE 技术 对于数据库 我将创建一个 DBManager 我应该在这里应用单例模式还是将其所有方法设为静态 我将使用这个 DBManager 进
  • c和java语言中的换行符

    现在行分隔符取决于系统 但在 C 程序中我使用 n 作为行分隔符 无论我在 Windows 还是 Linux 中运行它都可以正常工作 为什么 在java中 我们必须使用 n 因为它与系统相关 那么为什么我们在c中使用 n 作为新行 而不管我
  • 按文件名过滤 eclipse 中的警告

    我们使用 Eclipse 进行 Java 开发 并使用 Maven 将 JSP 编译成 servlet 以便在嵌入式 Jetty 实例中使用 这意味着要从 Eclipse 运行该项目 我必须包含 target jsp source 作为源文
  • SwingWorker 在另一个 SwingWorker 的 did 方法中

    首先 我需要通知您 我正在尽最大努力学习如何用 Java 编写代码 虽然有点困难 但我相信我能做到 我过去提交了几个有关 SwingWorkers 等的问题 每一个我都以为我已经做到了 但后来发现我仍然需要学习 希望这一次不是那样的一次 话
  • 为什么我要使用责任链而不是 switch 语句

    考虑一下您已经获得了多次验证 仅当要检查的对象属于某种类型时 这些验证才应生效 为什么我要使用责任链而不是 switch 语句 责任链示例 public class Executor Inject private ValidatorFact
  • 如何使用 Selenium 中的索引切换到窗口

    由于selenium不提供切换到窗口 多个窗口 的方法 但我想使用index html自定义方法来切换到不同的窗口 但下面的代码没有按预期工作 请建议以下方法的最佳实施 public void switchToWindowIndex int
  • 如何在 JdbcTemplate 中创建 mySQL 存储过程

    背景 为了解决 MySql 中某些语句只允许在存储过程中出现的问题 我尝试在 JdbcTemplate 提交的 sql 中创建 运行然后删除存储过程 一个简单的例子是 这恰好是在 Spring Boot 中 Service public c
  • 在 Java 中创建带注释的对象时收到通知

    Intent 我有一个自定义 Java 注释 DynamicField public class RESTEndpointInvoker DynamicField key httpTimeout private long httpTimeo
  • selenium webdriver 中的多个程序执行不起作用

    Selenium WebDriver 中的多个程序执行不起作用 我编写了 1 个 testNG xml 文件和 2 个 java 类 我尝试从 xml 文件运行这两个 java 类 但这不起作用 XML代码
  • 两条腿的 OAuth 和 Gmail Atom feed

    我们正在尝试让 2 legged OAuth 与 Gmail Atom feed 一起使用 我们使用 John Kristian Praveen Alavilli 和 Dirk Ba lfanz 贡献的 Java 库 http oauth
  • 如何允许Spring Boot中启用CORS的所有请求?

    In my 弹簧靴应用程序 目前我有这样的课程 SpringBootApplication public class TestApplication public static void main String args SpringApp
  • java中日期转换dd-MMM-yyyy到dd-MM-yyyy

    在Java中将23 Mar 2011转换为23 03 2011的最简单方法是什么 感谢大家 这似乎解决了这个问题 try Calendar cal Calendar getInstance cal setTime new SimpleDat
  • JFrame Glasspane 也优于 JDialog,但不应该

    我有一个带有 Glasspane 的 JFrame 未装饰 该框架打开一个 JDialog 也未装饰 也有一个 glassPane 并隐藏自身 setVisible false Glasspanes 通过 setGlassPane 设置 对
  • Java 中更高级的泛型

    假设我有以下课程 public class FixExpr Expr
  • 如何使 JScrollPane 与嵌套 JPanel 一起正常工作?

    我正在使用 NetBeans 在 Java 中构建 Swing 应用程序 但我遇到布局问题 我的主框架包含一个JScrollPane其中包含一个JPanel called contentPanel其中又包含一个JPanel called l
  • Spring Boot 访问 H2 控制台

    我有一个基本的 Spring Boot 应用程序 嵌入式 Tomcat Thymeleaf 模板引擎 我创建了这个 bean 来访问控制台 Bean public ServletRegistrationBean h2ConsoleServl
  • Retrofit 2.0:预期为 BEGIN_OBJECT,但在第 1 行第 1 列路径 $ [重复] 处为 STRING

    这个问题在这里已经有答案了 我在邮递员上传递了更新用户请求并获得了成功的响应 参见图片 现在当我尝试使用 Retrofit 2 在我的应用程序中执行相同操作时 出现错误 com google gson JsonSyntaxException
  • 获取Java中ResultSet返回的行数

    我用过一个ResultSet返回一定数量的行 我的代码是这样的 ResultSet res getData if res next System out println No Data Found while res next code t
  • 使用 PDFBox 在 Android 中创建 PDF

    我正在尝试通过我的 Android 应用程序创建 PDFPDFBoxapi 但出现以下错误 java lang NoClassDefFoundError org apache pdfbox pdmodel PDDocument 我已经将以下

随机推荐