当前位置: 首页 > 知识库问答 >
问题:

手动验证使用Spring安全性

田兴朝
2023-03-14

我正在使用Spring Security性,它工作正常,但现在我想手动启动安全过程,对客户端进行更改,我需要在我的控制器中获取用户名和密码(表单不会直接调用“j_spring_security_check”)

我想到了两个选项,我有一些问题:

>

  • 在我得到参数并做了一些事情之后,我将向j_spring_security_checkurl发送一个post请求。我的代码:

    公共无效测试(loginDTO loginDTO) {

    MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
    HttpHeaders headers = new HttpHeaders();
    
    body.add(
         "j_username",
         loginDTO.getJ_username());
    
    body.add(
         "j_password",
         loginDTO.getJ_password());
    
    HttpEntity<?> httpEntity = new HttpEntity<Object>(
                              body, headers);
    headers.add(
            "Accept",
            MediaType.APPLICATION_JSON_VALUE);
    restTemplate.exchange(
                  "http://localhost:8080/XXX/j_spring_security_check",
                  HttpMethod.POST,
                  httpEntity,
                  HttpServletResponse.class);
    } 
    

    这不工作,我得到:500内部服务器错误,为什么?

    >

  • 第二个选项-我执行了以下操作:

    public void test2(loginDTO loginDTO, HttpServletRequest request) {
    
      UsernamePasswordAuthenticationToken token =
                    new UsernamePasswordAuthenticationToken(
                              loginDTO.getJ_username(),
                              loginDTO.getJ_password());
    
      token.setDetails(new WebAuthenticationDetails(request));
      Authentication authentication = this.authenticate(token);
    
      SecurityContextHolder.getContext().setAuthentication(authentication);
    
      this.sessionRegistry.registerNewSession(
                        request.getSession().getId(),
                        authentication.getPrincipal());
    }
    

    问题是在身份验证上没有调用成功。感觉不对,我错过了使用Spring安全的意义。

    正确的原因是什么?

  • 共有3个答案

    朱淮晨
    2023-03-14

    好吧,所以我结合了@Ralph和@manish答案,这就是我所做的:

    (二角色身份验证筛选是用户名密码身份验证筛选的扩展)

     public void manualAuthentication(loginDTO loginDTO, HttpServletRequest request, HttpServletResponse response) throws IOException,
            ServletException {
    
        AddableHttpRequest addableHttpRequest = new AddableHttpRequest(
                                           request);
    
        addableHttpRequest.addParameter(
                        "j_username",
                        loginDTO.getJ_username());
        addableHttpRequest.addParameter(
                        "j_password",
                        loginDTO.getJ_password());
    
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) twoFactorAuthenticationFilter.attemptAuthentication(
                                                                              addableHttpRequest,
                                                                              response);
        if (token.isAuthenticated()) {
            twoFactorAuthenticationFilter.successfulAuthentication(
                                       addableHttpRequest,
                                       response,
                                       null,
                                       token);
        }
    
    
        }
    

    它工作正常

    江英卓
    2023-03-14

    当您想尽可能多地使用正常的身份验证过程时,您可以创建一个包含登录名和密码的mockedHttpServletRequestHttpServletResponseorg.springframework.mock.web.MockHttpServletRequestorg.springframework.mock.web.MockHttpServletResponse),然后调用

     UsernamePasswordAuthenticationFilter.attemptAuthentication(
                HttpServletRequest request,
                HttpServletResponse response)`
    

    之后,您还需要调用SessionAuthenticationStrategy.onAuthentication(…)成功身份验证(…)

    由于私人领域,这有点棘手,所以这是我的解决方案

    public class ExtendedUsernamePasswordAuthenticationFilter
                               extends UsernamePasswordAuthenticationFilter {
    
    
        @Override
        public void manualAuthentication(String login,
                                         String password,
                                         HttpServletRequest httpServletRequest)
                                  throws IOException, ServletException {
    
            /** I do not mock the request, I use the existing request and
                manipulate them*/
            AddableHttpRequest addableHttpRequest =
                                      new AddableHttpRequest(httpServletRequest);
            addableHttpRequest.addParameter("j_username", login);
            addableHttpRequest.addParameter("j_password", password);
    
            MockHttpServletResponse mockServletResponse =
                                      new MockHttpServletResponse();
            Authentication authentication = this.attemptAuthentication(
                                                    addableHttpRequest,
                                                    mockServletResponse);
    
            this.reflectSessionStrategy().onAuthentication(
                                            authentication,
                                            addableHttpRequest,
                                            mockServletResponse);
            this.successfulAuthentication(addableHttpRequest,
                                          mockServletResponse,
                                          authentication);
        }
    
        private SessionAuthenticationStrategy reflectSessionStrategy() {
    
            Field sessionStrategyField =
                          ReflectionUtils.findField(
                                 AbstractAuthenticationProcessingFilter.class,
                                 "sessionStrategy",
                                 SessionAuthenticationStrategy.class);
            ReflectionUtils.makeAccessible(sessionStrategyField);
    
            return (SessionAuthenticationStrategy)
                   ReflectionUtils.getField(sessionStrategyField, this);
        }
    }
    

    < code>AddableHttpRequest就像一个基于真实请求的模拟

    public class AddableHttpRequest extends HttpServletRequestWrapper {
    
        /** The params. */
        private HashMap<String, String> params = new HashMap<String, String>();
    
    
        public AddableHttpRequest(HttpServletRequest request) {
            super(request);
        }
    
        @Override
        public String getMethod() {
            return "POST";
        }
    
        @Override
        public String getParameter(final String name) {
            // if we added one, return that one
            if (params.get(name) != null) {
                return params.get(name);
            }
            // otherwise return what's in the original request
            return super.getParameter(name);
        }
    
        public void addParameter(String name, String value) {
            params.put(name, value);
        }    
    }
    

    另一种方法是实现您自己的身份验证过滤器。这是一个调用身份验证管理器的类。.但是这个类也负责调用有关身份验证的所有内容(抽象身份验证处理过滤器.doFilter所做的)”

    司空凌
    2023-03-14

    我通常会做以下事情:

    @Controller
    public class AuthenticationController
    {
      @Autowired
      AuthenticationManager authenticationManager;
    
      @Autowired
      SecurityContextRepository securityContextRepository;
    
      @RequestMapping(method = Array(RequestMethod.POST), value = Array("/authenticate"))
      public String authenticate(@RequestParam String username, @RequestParam String password, HttpServletRequest request, HttpServletResponse response)
      {
        Authentication result = this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    
        SecurityContextHolder.getContext.setAuthentication(result);
    
        this.securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
    
        return "successView";
      }
    }
    

    使用这种方法的原因是:

    1. 非常简单,如果您忽略异常处理等,只需几行代码。
    2. 利用现有的Spring Security组件。
    3. 使用应用程序配置中配置的Spring Security组件,并允许在需要时更改它们。例如,可以针对RDBMS、LDAP、Web服务、Active Directory等进行身份验证,而无需自定义代码担心。
     类似资料:
    • 我正在尝试通过连接到LDAP使用Spring Security进行我的第一个演示。 我使用的Sping版本是:3.1.0.RELEASE 以下是我的security-integration.xml: 然而,每当我部署我的战争时,我都会遇到这个例外: HTTP状态500 - 类型异常报告 消息 描述服务器遇到一个内部错误(),该错误阻止它完成此请求。 例外情况 javax.servlet。Servl

    • 问题内容: 我正在使用Hibernate和Spring Annotations进行很多验证,如下所示: 然后在控制器中,在参数中调用它: 但是我想根据控制器方法中的某些逻辑来决定使用的组。有没有办法手动调用验证?像什么? 我知道要创建自己的Validator类,但是这是我要避免的事情,我宁愿只在类变量本身上使用批注。 问题答案: 比 Jaiwo99 更进一步: 如果您有兴趣,还可以指向SmartV

    • 我正在尝试让JDBC身份验证与我的小辅助项目一起工作,从表面上看,它应该可以工作,但它没有。所有的配置都遵循贝娄。 如果我切换到具有相同用户名/密码的inMemory身份验证,它就会非常工作。 这是我记录输出时得到的结果:

    • 问题内容: 从JSON请求正文创建POJO字段时,带注释的spring验证有效。但是,当我手动(使用设置器)创建同一对象并想要触发验证时,我不确定该怎么做。 这是Registration类,它具有可以构建对象的Builder内部类。在构建方法中,我想触发弹簧验证。请滚动到底部并检查Builder.build()和Builder.valiate()方法以查看当前的实现。我正在使用javax.vali

    • 当POJO的字段从json请求体创建时,它的注释Spring验证工作。但是,当我手动(使用setters)创建相同的对象并希望触发验证时,我不确定如何做到这一点。 下面是注册类,它具有可以构建对象的生成器内部类。在构建方法中,我想触发spring验证。请滚动到底部并检查生成器。build()和Builder。valiate()方法来查看当前的实现。我在用javax。验证。Validator触发验证