基于请求参数的Spring安全认证

时间:2013-11-05 14:33:52

标签: spring authentication spring-security url-parameters

我正在使用的应用程序已经有Spring Security来处理基于表单的身份验证。现在要求是通过外部服务以编程方式登录用户,如果在其中一个请求参数中找到令牌。

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

我无法弄清楚如何以及在何处“触发”或“挂钩”Spring Security来检查此参数并进行验证,然后在适当时对用户进行身份验证,因为没有登录表单。我认为Spring Security中应该有一些可以扩展或自定义的东西来做到这一点吗?

我查看了Spring Security文档并想知道AbstractPreAuthenticatedProcessingFilter是否适合开始使用?

2 个答案:

答案 0 :(得分:22)

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

您需要像这样创建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;
    }
}

您还需要创建Filter以将自定义参数转换为身份验证令牌:

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" />

最后,您需要将这些bean连接到您的安全配置中(相应地进行调整):

<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)。

答案 1 :(得分:4)

如果您使用Spring MVC控制器或服务,其中传递了target请求参数,那么您可以使用@PreAuthorize Spring安全注释。

比如说,你有一些Spring服务可以检查传递的令牌并在传递令牌有效时执行身份验证:

@Service("authenticator")
class Authenticator {        
...
public boolean checkTokenAndAuthenticate(Object token) {
    ...
    //check token and if it is invalid return "false"
    ...
    //if token is valid then perform programmatically authentication and return "true"  
}
...             
}    

然后,使用Spring security @PreAuthorize注释,您可以在下一步执行此操作:

...
@PreAuthorize("@authenticator.checkTokenAndAuthenticate(#token)")
public Object methodToBeChecked(Object token) { ... }
...

此外,您应该启用Spring安全注释并将spring-security-aspects添加到POM(或jar到classpath)。