基于请求参数的Spring安全认证 [英] Spring security authentication based on request parameter
问题描述
我正在开发的应用程序已经有 Spring Security 来处理基于表单的身份验证.现在的要求是通过外部服务以编程方式登录用户如果在请求参数之一中找到令牌.
The application I'm working on already has Spring Security to handle form based authentication. Now the requirement is to login a user programmatically via an external service if a token is found in one of the request parameters.
换句话说,如果一个特定的请求参数,比如令牌",存在,它需要使用该令牌调用一个外部服务来验证它是否是一个有效的令牌.如果是,则用户将登录.
In other words, if a particular request parameter, say "token", exists, it needs to call an external service with that token to verify if it's a valid token. If it is then the user will be logged in.
我不知道如何以及在何处触发"或连接到"Spring Security 以检查此参数并进行验证,然后在适当的时候对用户进行身份验证,因为没有登录表单.我认为 Spring Security 中应该有一些可以扩展或定制的东西来做到这一点?
I can't figure out how and where to "trigger" or "hook on to" Spring Security to check this parameter and make the verification then authenticate the user when appropriate since there is no login form. I thought there should be something in Spring Security that can be extended or customized to do this?
我查看了 Spring Security 文档,想知道 AbstractPreAuthenticatedProcessingFilter 是否适合开始?
I looked through Spring Security documentation and wonder if AbstractPreAuthenticatedProcessingFilter is the right thing to start with?
推荐答案
我的应用程序中有类似的设置.据我所知,以下是基本要素:
I have a similar setup in my application. Here are the basic elements as far as I can tell:
您需要像这样创建一个 AuthenticationProvider
:
You need to create an AuthenticationProvider
like so:
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
以将自定义参数转换为身份验证令牌:
You also need to create a Filter
to turn the custom parameter into an authentication token:
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:
You need to create beans for these:
<beans:bean id="authTokenFilter" class="com.example.security.AuthenticationTokenFilter" scope="singleton" />
<beans:bean id="tokenAuthProvider" class="com.example.security.TokenAuthenticationProvider" />
最后,您需要将这些 bean 连接到您的安全配置中(相应地调整):
Finally, you need to wire these beans into your security config (adjust accordingly):
<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).
There might be another way, but this definitely works (using Spring Security 3.1 at the moment).
这篇关于基于请求参数的Spring安全认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!