JAX-RS-EJB中的SecurityContext为空

如何解决JAX-RS-EJB中的SecurityContext为空

我的后端JAX-RS应用程序中存在与我的EJB中的SecurityContext null有关的问题。

该应用程序涉及Users和Todo对象。一个用户可以有许多待办事项,这些待办事项基本上是表示便利贴的对象,描述了要做的事情。

我的项目中类的一般结构如下:

前端------> SecurityFilter->资源类(JAX-RS)->服务类(EJB)-> DB

对于此特定示例,这些类是:

前端------> SecurityFilter.java -> TodoRest.java(JAX-RS)-> TodoService.java(EJB)->数据库

将方法公开到前端的资源类称为“ TodoRest”,它具有一个名为getTodosByTodoUser的方法,该方法返回用户的所有待办事项。

由于此方法使用@Authz进行注释(报告如下:它是将方法链接到我的SecurityFilter的注释类),因此当我们调用它时,将触发SecurityFilter类。

这是 SecurityFilter 类:

package academy.learnprogramming.config;
 
import academy.learnprogramming.services.SecurityUtil;
import academy.learnprogramming.utils.Constants;
import io.jsonwebtoken.Jwts;
import org.apache.log4j.Logger;
 
import javax.annotation.Priority;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.Priorities;
import java.io.IOException;
import java.security.Key;
import java.security.Principal;
 
@Provider
@Authz
@Priority(Priorities.AUTHENTICATION)
public class SecurityFilter implements ContainerRequestFilter {
 
    @Inject
    private Logger LOG;
 
    @Inject
    SecurityUtil securityUtil;
 
    @Inject
    private ApplicationState applicationState;
 
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
 
        String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
        if(authHeader == null || authHeader.isEmpty() || !authHeader.startsWith(Constants.AUTH_TOKEN_BEARER_PREFIX)) {
            LOG.error("Wrong or no authorization header found: " + authHeader);
            //TODO - Beautify this exception
            throw new NotAuthorizedException(Response
                    .status(Response.Status.UNAUTHORIZED)
                    .entity("No authorization header provided")
                    .build());
        }
 
        String token = authHeader.substring(Constants.AUTH_TOKEN_BEARER_PREFIX.length()).trim();
        String email = applicationState.getEmail();
        try {
            //TODO - Parse the token
 
            LOG.info("applicationState.getEmail(): " + email);
            Key key = securityUtil.generateKey(applicationState.getEmail());
 
            //If it doesn't throw exception,then the token is valid
            Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody()
                    .getSubject()
                    .equals(applicationState.getEmail());
 
            LOG.info("originalSecurityContext.getUserPrincipal before the token setting: " + requestContext.getSecurityContext().getUserPrincipal());
 
            SecurityContext originalSecurityContext = requestContext.getSecurityContext();
 
            requestContext.setSecurityContext(new SecurityContext() { // <---------- THIS IS THE CHANGE OF THE SECURITY CONTEXT
 
                @Override
                public Principal getUserPrincipal() {
                    return new Principal() {
                        @Override
                        public String getName() {
                            return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody().getSubject();
                        }
                    };
                }
 
                @Override
                public boolean isUserInRole(String role) {
                    return originalSecurityContext.isUserInRole(role);
                }
 
                @Override
                public boolean isSecure() {
                    return originalSecurityContext.isSecure();
                }
 
                @Override
                public String getAuthenticationScheme() {
                    return originalSecurityContext.getAuthenticationScheme();
                }
            });
 
            LOG.info("securityContext.getUserPrincipal after the token setting: " + requestContext.getSecurityContext().getUserPrincipal().getName());
            LOG.debug("User identified by mail " + applicationState.getEmail() + " - Token parsed successfully: " + token);
            LOG.info("Token parsed successfully");
 
        } catch (Exception e) {
            LOG.error("Invalid token: " + token);
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }
 
     }
}

SecurityFilter类成功更改了请求的SecurityContext,将用户电子邮件作为主体插入。实际上,我在TodoRest类中注入了SecurityContext(带有@Context注释)(在下面进行报告),​​并且在执行过滤器之后,我在getTodosByTodoUser方法中记录了securityContext.getUserPrincipal(),该方法正确地返回了请求的用户电子邮件。

这是JAX-RS TodoRest 类:

package academy.learnprogramming.rest;
 
import academy.learnprogramming.config.Authz;
import academy.learnprogramming.dto.TodoDTO;
import academy.learnprogramming.entities.Todo;
import academy.learnprogramming.entities.TodoUser;
import academy.learnprogramming.services.TodoService;
import academy.learnprogramming.services.TodoUserService;
import academy.learnprogramming.utils.Constants;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
 
@Path("todo")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class TodoRest {
 
    @Inject
    private Logger LOG;
 
    @Inject
    TodoService todoService;
 
    @Inject
    TodoUserService todoUserService;
 
    @Context
    SecurityContext securityContext;
 
    @Authz
    @Path("new")
    @POST
    public Response createTodo(Todo todo) {
        LOG.info("rest service - createTodo");
        todoService.createTodo(todo);
        return Response.ok(todo).build();
    }
 
    @Authz
    @Path("todosByTodoUser")
    @GET
    public List<Todo> getTodosByTodoUser(TodoUser todoUser) {
        LOG.info("securityContext: " + securityContext.getUserPrincipal().getName()); // <---------- HERE I LOG THE SECURITY CONTEXT,WHICH IS CORRECTLY CHANGED BY SECURITY FILTER CLASS
        return todoService.getAllTodos();
 
    }
}

现在在getTodosByTodoUser中,我将调用TodoService EJB,并在其中注入了SecurityContext。可悲的是,在EJB内部,SecurityContext是nullB,我无法检索到getUserPrincipal()。

这是EJB TodoService 类:

package academy.learnprogramming.services;
 
import academy.learnprogramming.entities.Todo;
import academy.learnprogramming.entities.TodoUser;
import org.apache.log4j.Logger;
import org.dozer.DozerBeanMapper;
 
import javax.annotation.PostConstruct;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import java.util.List;
 
@Stateless
public class TodoService {
 
    @Inject
    private Logger LOG;
 
    @Inject
    private EntityManager entityManager;
 
    @Inject
    private TodoUserService todoUserService;
 
    @Inject
    private DozerBeanMapper dozenBeanMapper;
 
    @Context
    SecurityContext securityContext;
 
 
    private String todoUserEmail;
 
    @PostConstruct
    private void init() {
        //TODO - Get user mail
        todoUserEmail = "";
    }
 
    public Todo createTodo(Todo todo) {
        //Persist into db
        TodoUser todoUser = todoUserService.findUserByEmail(todo.getTodoOwner().getEmail());
        if(todoUser != null) {
            todo.setTodoOwner(todoUser);
            todoUser.getTodos().add(todo);
            entityManager.persist(todo);
        }
        return todo;
    }
 
 
    public List<Todo> getAllTodos() {
        String securityContextEmail = securityContext.getUserPrincipal().getName();  // <---------- NULL,everything explodes
        LOG.info("securityContextEmail:" + securityContextEmail);
 
        List<Todo> todos = entityManager.createNamedQuery(Todo.TODO_FIND_ALL_TODOS_BY_OWNER,Todo.class)
                .setParameter("email",securityContext.getUserPrincipal().getName())
                .getResultList();
 
        return todos;
    }
 
    public List<Todo> getAllTodosByTask(String taskText) {
        return entityManager.createNamedQuery(Todo.TODO_FIND_TODO_BY_TASK,Todo.class)
                .setParameter("task","%" + taskText + "%")
                .setParameter("email","alessandro@provamail.com")
                .getResultList();
    }
 
 
}

为完整起见,我添加了 @Authz 注释类,该注释类将注释@Authz链接到SecurityFilter类:

package academy.learnprogramming.config;

import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Authz {

}

我在线检查了,发现:

  • 有人在方法内部将securityContext从REST类传递到EJB服务类,但这非常丑陋,因为我们必须为每个方法传递securityContext;
  • 有人使用@EJBContext,但是我尝试使用它而没有成功。

有人可以帮助我了解我在做什么错吗? 我特别想了解:

  • 如何将安全上下文从Jax-RS类传播到ejb bean?
  • 是否按照我的预期自动管理了安全信息?或..
  • 是否需要改进或添加其他jboss-?. xml配置文件?或..
  • 我是否需要在调用的Jax-RS Bean中进行某些更改,以便将安全信息传播到被调用的bean?或..
  • 我是否假设有不正确的地方?

非常感谢您的宝贵时间。

编辑:我添加了此链接,他们说他们有解决办法,但引用的页面不再存在。 JAX-RS + EJB,SecurityContext inside ejb is null,on WildFly 10.1。 我尝试按照解决方案的建议进行操作,但是没有用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res