J'ai une api de repos où je m'authentifie à l'aide de l'autorisation de base Spring Security où le client envoie le nom d'utilisateur et le mot de passe pour chaque demande. Maintenant, je voulais implémenter une authentification basée sur un jeton où je vais envoyer un jeton dans l'en-tête de la réponse lorsque l'utilisateur est authentifié au début. Pour les autres demandes, le client peut inclure ce jeton dans l'en-tête qui sera utilisé pour authentifier l'utilisateur auprès des ressources. J'ai deux fournisseurs d'authentification tokenAuthenticationProvider et daoAuthenticationProvider
@Component
public class TokenAuthenticationProvider implements AuthenticationProvider {
@Autowired
private TokenAuthentcationService service;
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
final HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
final String token = request.getHeader(Constants.AUTH_HEADER_NAME);
final Token tokenObj = this.service.getToken(token);
final AuthenticationToken authToken = new AuthenticationToken(tokenObj);
return authToken;
}
@Override
public boolean supports(final Class<?> authentication) {
return AuthenticationToken.class.isAssignableFrom(authentication);
}
}
Et dans daoAuthenticationProvider, je suis en train de définir userDetailsService personnalisé et de l'authentifier en fonction des informations de connexion de l'utilisateur en le récupérant dans la base de données (qui fonctionne correctement tant que le nom d'utilisateur et le mot de passe sont transmis à l'aide de Authorization: Basic bGllQXBpVXNlcjogN21wXidMQjRdTUR = 0 en tant qu'en-tête)
Mais lorsque j'inclus un jeton dans l'en-tête à l'aide de X-AUTH-TOKEN (Constants.AUTH_HEADER_NAME), tokenAuthenticationProvider n'est pas appelé. Je reçois l'erreur comme
{"timestamp":1487626368308,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/find"}
Et voici comment j'ajoute des fournisseurs d'authentification.
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
final UsernamePasswordAuthenticationProvider daoProvider = new
UsernamePasswordAuthenticationProvider(this.service, this.passwordEncoder());
auth.authenticationProvider(this.tokenAuthenticationProvider);
auth.authenticationProvider(daoProvider);
}
Suggérez-nous comment mettre en œuvre l'authentification par jeton sans nuire au comportement actuel de la sécurité de Spring.
Voici comment j'ai pu implémenter l'authentification par jeton et l'authentification de base
SpringSecurityConfig.Java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(this.participantService).passwordEncoder(this.passwordEncoder());
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
//Implementing Token based authentication in this filter
final TokenAuthenticationFilter tokenFilter = new TokenAuthenticationFilter();
http.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class);
//Creating token when basic authentication is successful and the same token can be used to authenticate for further requests
final CustomBasicAuthenticationFilter customBasicAuthFilter = new CustomBasicAuthenticationFilter(this.authenticationManager() );
http.addFilter(customBasicAuthFilter);
}
}
TokenAuthenticationFilter.Java
public class TokenAuthenticationFilter extends GenericFilterBean
{
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException
{
final HttpServletRequest httpRequest = (HttpServletRequest)request;
//extract token from header
final String accessToken = httpRequest.getHeader("header-name");
if (null != accessToken) {
//get and check whether token is valid ( from DB or file wherever you are storing the token)
//Populate SecurityContextHolder by fetching relevant information using token
final User user = new User(
"username",
"password",
true,
true,
true,
true,
authorities);
final UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
CustomBasicAuthenticationFilter.Java
@Component
public class CustomBasicAuthenticationFilter extends BasicAuthenticationFilter {
@Autowired
public CustomBasicAuthenticationFilter(final AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void onSuccessfulAuthentication(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response, final Authentication authResult) {
//Generate Token
//Save the token for the logged in user
//send token in the response
response.setHeader("header-name" , "token");
}
}
Comme notre CustomBasicAuthenticationFilter a été configuré et ajouté en tant que filtre à la sécurité du ressort,
Chaque fois que l'authentification de base réussit, la demande est redirigée vers onSuccessfulAuthentication où nous définissons le jeton et l'envoyons dans la réponse avec un en-tête "nom-en-tête".
Si "nom-en-tête" est envoyé pour une requête ultérieure, la requête passe d'abord par TokenAuthenticationFilter avant de tenter une authentification de base.
Vous pouvez essayer de définir votre jeton personnalisé AuthenticationToken
dans votre filtre d'authentification, par exemple:
public class AuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final String authTokenHeader = ((HttpServletRequest)request).getHeader(Constants.AUTH_HEADER_NAME);
if (authTokenHeader != null) {
SecurityContextHolder.getContext().setAuthentication(createAuthenticationToken(authTokenHeader));
}
chain.doFilter( request, response );
}
}