Spring Security - Token basierte API Auth & amp; Benutzer / Passwort-Authentifizierung
Ich versuche zum erstellen einer webapp wird in Erster Linie bieten eine REST-API mithilfe der Frühling, und bin versucht, konfigurieren Sie die security-Seite.
Ich versuche zu implementieren, die diese Art von Muster: https://developers.google.com/accounts/docs/MobileApps (Google verändert, dass die Seite so keinen Sinn mehr macht - siehe die Seite meinte ich hier: http://web.archive.org/web/20130822184827/https://developers.google.com/accounts/docs/MobileApps)
Hier ist, was ich brauche, um accompish:
- Web-app hat einfache, sign-in/sign-up-Formulare, die die Arbeit mit normalen Frühling Benutzer/Kennwort-Authentifizierung (getan haben, diese Art der Sache vor mit dao/authenticationmanager/userdetailsservice etc)
- REST api-Endpunkte, auf stateless sessions und jede Anforderung authentifiziert basierend ona-token zur Verfügung gestellt, mit der Aufforderung,
werden(z.B. Benutzer-logins/Zeichen mit den normalen Formen, die webapp bietet Sicheres cookie mit dem token, das verwendet werden kann in folgende API-Anfragen)
Ich hatte eine normale Authentifizierung setup wie folgt:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mobile/app/sign-up").permitAll()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/?loginFailure=true")
.permitAll();
}
Ich dachte an das hinzufügen eines pre-auth-filter, der überprüft, ob das token in der Anfrage und dann legt den Sicherheitskontext (würde das bedeuten, dass die normalen nach Authentifizierung übersprungen wird?), aber über die normale Benutzer/Passwort habe ich nicht allzu viel getan, mit token-basierte Sicherheit, aber basierend auf einige andere Beispiele, die ich kam mit die folgenden:
Security Config:
@Override protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilter(restAuthenticationFilter())
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
.antMatcher("/v1/**")
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/mobile/app/sign-up").permitAll()
.antMatchers("/v1/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/loginprocess")
.failureUrl("/?loginFailure=true")
.permitAll();
}
Meine eigene rest-filter:
public class RestAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public RestAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
private final String HEADER_SECURITY_TOKEN = "X-Token";
private String token = "";
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
this.token = request.getHeader(HEADER_SECURITY_TOKEN);
//If we have already applied this filter - not sure how that would happen? - then just continue chain
if (request.getAttribute(FILTER_APPLIED) != null) {
chain.doFilter(request, response);
return;
}
//Now mark request as completing this filter
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
//Attempt to authenticate
Authentication authResult;
authResult = attemptAuthentication(request, response);
if (authResult == null) {
unsuccessfulAuthentication(request, response, new LockedException("Forbidden"));
} else {
successfulAuthentication(request, response, chain, authResult);
}
}
/**
* Attempt to authenticate request - basically just pass over to another method to authenticate request headers
*/
@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
AbstractAuthenticationToken userAuthenticationToken = authUserByToken();
if(userAuthenticationToken == null) throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token"));
return userAuthenticationToken;
}
/**
* authenticate the user based on token, mobile app secret & user agent
* @return
*/
private AbstractAuthenticationToken authUserByToken() {
AbstractAuthenticationToken authToken = null;
try {
//TODO - just return null - always fail auth just to test spring setup ok
return null;
} catch (Exception e) {
logger.error("Authenticate user by token error: ", e);
}
return authToken;
}
Oben führt tatsächlich zu einem Fehler bei app-Start zu sagen: authenticationManager must be specified
Kann mir jemand sagen, wie man am besten, dies zu tun - ist ein pre_auth filter der beste Weg, dies zu tun?
BEARBEITEN
Schrieb ich, was ich gefunden habe und wie ich es gemacht habe mit Spring-security (einschließlich code) Implementierung einer standard-token-Implementierung (nicht OAuth)
Überblick über die Problematik und die Herangehensweise/Lösung
Die Implementierung der Lösung mit Spring-security
Hoffe, es hilft einigen anderen.
InformationsquelleAutor der Frage rhinds | 2014-02-24
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube, die Fehler, die Sie erwähnen, ist, nur weil die
AbstractAuthenticationProcessingFilter
Basis-Klasse, die Sie verwenden, erfordert eineAuthenticationManager
. Wenn Sie nicht gehen, um es zu verwenden können Sie es zu einem no-op, oder einfach nur implementierenFilter
direkt. Wenn IhrFilter
können die Authentifizierung der Anforderung und legt dieSecurityContext
dann in der Regel die downstream-Verarbeitung wird übersprungen (es hängt von der Implementierung der downstream-Filter, aber ich sehe nicht, etwas seltsam in Ihrer app, so dass Sie wahrscheinlich alle Verhalten sich so).Wenn ich du wäre, könnte in Erwägung ziehen, die API-Endpunkte in eine vollständig separate filter-chain (ein weiteres
WebSecurityConfigurerAdapter
bean). Aber das macht alles nur einfacher zu Lesen, nicht unbedingt entscheidend.Finden Sie vielleicht (als Vorschlag in den Kommentaren), dass Sie am Ende das Rad neu erfinden, aber ein Versuch nicht Schaden, und Sie werden wahrscheinlich lernen Sie mehr über Frühling und Sicherheit in den Prozess.
ZUSATZ: github Ansatz ist ganz interessant: Benutzer verwenden einfach den token als Passwort im basic-auth, und der server nicht, müssen Sie einen benutzerdefinierten filter (
BasicAuthenticationFilter
ist in Ordnung).InformationsquelleAutor der Antwort Dave Syer