Problemă: Avem o Primăvară MVC-based API Odihnitor care conține informații sensibile. API ar trebui să fie asigurată, cu toate acestea a trimite utilizatorului's de conectare (user/pass combo) cu fiecare cerere nu este de dorit. Pe RESTUL liniilor directoare (interne și cerințele de afaceri), serverul trebuie să rămână fără cetățenie. API-ul va fi consumată de către un alt server într-un mashup-stil de abordare.
Cerinte:
Clientul face o cerere pentru a .../autentifica
(URL neprotejat) cu acreditări; serverul returnează un semn sigur care conține informații suficiente pentru server pentru a valida cererile viitoare și rămâne apatrizi. Acest lucru ar putea consta în aceleași informații ca Izvor de Securitate's - mi Amintesc-M-Token.
Clientul face cereri ulterioare la diverse (protejat), Url-uri, adăugarea obținut anterior semn ca un parametru de interogare (sau, mai puțin de dorit, o cerere HTTP antet).
Clientul nu poate fi de așteptat pentru a stoca cookie-uri.
Când ne-am folosi de Primăvară deja, soluția ar trebui să facă uz de Primăvară de Securitate.
Am'am fost dat cu capul de perete încercarea de a face acest lucru, așa că să sperăm că cineva de acolo a rezolvat deja această problemă.
Având în scenariul de mai sus, cum ar putea să rezolve această nevoie special?
Am reușit să obținem acest lucru exact așa cum este descris în programul operațional, și să sperăm că altcineva poate face uz de soluție. Aici's ce-am făcut:
Înființat context de securitate astfel:
<security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="CustomAuthenticationEntryPoint">
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/authenticate" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
<bean id="CustomAuthenticationEntryPoint"
class="com.demo.api.support.spring.CustomAuthenticationEntryPoint" />
<bean id="authenticationTokenProcessingFilter"
class="com.demo.api.support.spring.AuthenticationTokenProcessingFilter" >
<constructor-arg ref="authenticationManager" />
</bean>
După cum puteți vedea, am'am creat un custom AuthenticationEntryPoint
, care, practic, doar returnează o 401 Neautorizate dacă cererea a fost't autentificate în lanț de filtrare prin noastre AuthenticationTokenProcessingFilter
.
CustomAuthenticationEntryPoint:
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
}
}
AuthenticationTokenProcessingFilter:
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
@Autowired UserService userService;
@Autowired TokenUtils tokenUtils;
AuthenticationManager authManager;
public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
this.authManager = authManager;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
@SuppressWarnings("unchecked")
Map<String, String[]> parms = request.getParameterMap();
if(parms.containsKey("token")) {
String token = parms.get("token")[0]; // grab the first "token" parameter
// validate the token
if (tokenUtils.validate(token)) {
// determine the user based on the (already validated) token
UserDetails userDetails = tokenUtils.getUserFromToken(token);
// build an Authentication object with the user's info
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
// set the authentication into the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication));
}
}
// continue thru the filter chain
chain.doFilter(request, response);
}
}
Evident, TokenUtils
conține unele privat (și foarte specifice) codul și poate't fi ușor partajate. Aici's interfata:
public interface TokenUtils {
String getToken(UserDetails userDetails);
String getToken(UserDetails userDetails, Long expiration);
boolean validate(String token);
UserDetails getUserFromToken(String token);
}
Asta ar trebui să ai un start bun. Fericit de codificare. :)
S-ar putea lua în considerare Digest Autentificare de Acces. În esență, protocolul este după cum urmează:
Tot din această comunicare se face prin cap, care, ca jmort253 subliniază, în general, este mai sigur decât comunicarea materiale sensibile din parametrii url.
Digest Autentificare de Acces este susținută de Primăvara Securitate. Observați că, deși doctorii spun că trebuie să aveți acces la client's plain-text parola, te poți autentifica cu succes dacă aveți HA1 hash]3 pentru clientul tau.
Cu privire la jetoane care transportă informații, JSON Web Token-uri (http://jwt.io) este o tehnologie genial. Conceptul principal este de a încorpora elemente de informații (creanțe) în token-ul, și apoi semnarea tot token, astfel încât validarea end poate verifica dacă afirmațiile sunt într-adevăr de încredere.
Eu folosesc acest implementare Java: https://bitbucket.org/b_c/jose4j/wiki/Home
Există, de asemenea, un Izvor de module (de primăvară-securitate-jwt), dar nu am't uitat în ce-l susține.
De ce nu't de a începe să utilizați OAuth cu JSON WebTokens
http://projects.spring.io/spring-security-oauth/
OAuth2 este un standardizate authorization protocol/cadru. Ca pe Oficial OAuth2 caietul de sarcini:
Puteți găsi mai multe informații aici