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

基于请求参数的Spring Security认证

邢浩邈
2023-03-14

我正在开发的应用程序已经具有Spring Security来处理基于表单的身份验证。现在,如果在某个请求参数中发现了令牌,则需要通过外部服务以编程方式登录用户。

换句话说,如果存在一个特定的请求参数,比如“token”,它需要用该令牌调用一个外部服务来验证它是否是一个有效的令牌。如果是,则用户将登录。

我不知道如何以及在哪里“触发”或“挂钩”Spring Security来检查这个参数并进行验证,然后在适当的时候对用户进行身份验证,因为没有登录表单。我想Spring Security中应该有一些东西可以扩展或定制来做到这一点?

我浏览了Spring Security文档,想知道从AbstractPreAuthenticatedProcessingFilter开始是否正确?

共有1个答案

陆耀
2023-03-14

我的应用程序中也有类似的设置。以下是据我所知的基本要素:

您需要创建AuthenticationProvider,如下所示:

public class TokenAuthenticationProvider implements AuthenticationProvider {

    @Autowired private SomeService userSvc;

    @Override
    public Authentication authenticate(Authentication auth) throws AuthenticationException {
        if (auth.isAuthenticated())
            return auth;

        String token = auth.getCredentials().toString();
        User user = userSvc.validateApiAuthenticationToken(token);
        if (user != null) {
            auth = new PreAuthenticatedAuthenticationToken(user, token);
            auth.setAuthenticated(true);
            logger.debug("Token authentication. Token: " + token + "; user: " + user.getDisplayName());
        } else
            throw new BadCredentialsException("Invalid token " + token);
        return auth;
    }
}

您还需要创建筛选器来将自定义参数转换为身份验证令牌:

public class AuthenticationTokenFilter implements Filter {


    @Override
    public void init(FilterConfig fc) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
        SecurityContext context = SecurityContextHolder.getContext();
        if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
            // do nothing
        } else {
            Map<String,String[]> params = req.getParameterMap();
            if (!params.isEmpty() && params.containsKey("auth_token")) {
                String token = params.get("auth_token")[0];
                if (token != null) {
                    Authentication auth = new TokenAuthentication(token);
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
        }

        fc.doFilter(req, res);
    }

    @Override
    public void destroy() {

    }

    class TokenAuthentication implements Authentication {
        private String token;
        private TokenAuthentication(String token) {
            this.token = token;
        }
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return new ArrayList<GrantedAuthority>(0);
        }
        @Override
        public Object getCredentials() {
            return token;
        }
        @Override
        public Object getDetails() {
            return null;
        }
        @Override
        public Object getPrincipal() {
            return null;
        }
        @Override
        public boolean isAuthenticated() {
            return false;
        }
        @Override
        public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        }
        @Override
        public String getName() {
            // your custom logic here
        }
    }

 }

您需要为以下内容创建bean:

<beans:bean id="authTokenFilter" class="com.example.security.AuthenticationTokenFilter" scope="singleton" />
<beans:bean id="tokenAuthProvider" class="com.example.security.TokenAuthenticationProvider" />
<sec:http >
   <!-- other configs here -->
   <sec:custom-filter ref="authTokenFilter" after="BASIC_AUTH_FILTER" /> <!-- or other appropriate filter -->
</sec:http>

<sec:authentication-manager>
    <!-- other configs here -->
    <sec:authentication-provider ref="tokenAuthProvider" />
</sec:authentication-manager>

可能还有另一种方法,但这肯定有效(目前使用Spring Security 3.1)。

 类似资料:
  • 我正在使用Scala Play 2.6,并尝试使用依赖注入来实例化基于请求参数的服务类。如下面的示例代码所示,控制器类从查询字符串中获取支付方法 以及处理PayPal或信用卡付款的服务类 对于Play 2.5以后的版本,<code>Play。当前和已被弃用。 我有两个问题: 上面的示例代码是基于请求参数注入类的正确方法吗?还是有其他更好的方法? 对于Play 2.5/2.6,获得应用注射器的方式是

  • 可以在模板中直接使用$Request对象,直接输入它的属性或调用它的大部分方法,但只支持方法的第一个参数; // 调用Request对象的get方法 传入参数为id {$Request.get.id} // 调用Request对象的param方法 传入参数为name {$Request.param.name} // 调用Request对象的param方法 传入参数为post.post_title

  • 可以在模板中直接使用$Request对象,直接输入它的属性或调用它的大部分方法,但只支持方法的第一个参数; // 调用Request对象的get方法 传入参数为id {$Request.get.id} // 调用Request对象的param方法 传入参数为name {$Request.param.name} // 调用Request对象的param方法 传入参数为post.post_title

  • 我是Scala的新手。 我在用加特林做压力测试。 我能够进行一个Gatling测试,向WS发出请求,我将JSON响应保存在session变量中。响应是一个JSON数组,其中包含指向我的后端提供的图像的多个链接。 具体来说,第一个请求检索地图中的点,每个点都分配了一个图像,必须通过访问第一个WS响应提供的链接来获取每个图像。 我有以下代码: 第一个WS的JSON响应示例: 第一个请求工作正常,我不使

  • 我正在使用spring-boot 2.3.9和spring-security以及keycloak 12.0.4。 和我的服务bean创建配置 编辑:这可能与Spring-Cloud-Starter-Sleuth有关。如果我移除这个依赖关系,所有的事情就会像预期的那样工作。但我也需要侦探。

  • Making authenticated requests(请求身份验证) 通过 access tokens 进行身份验证 在REST URL中使用当前用户ID 删除 access token 应用中,创建和验证用户的基础流程过程是: 注册用户通过 User.register(), 继承 PersistedModel 对象 使用 User.login(), 让用户在客户端获得 access tok