web-dev-qa-db-fra.com

Est-il possible d'utiliser l'authentification au porteur pour les demandes de mise à niveau Websocket?

La demande de mise à niveau pour l'ouverture d'une connexion Websocket est une demande HTTP standard. Côté serveur, je peux authentifier la demande comme une autre. Dans mon cas, je voudrais utiliser l'authentification au porteur. Malheureusement, il n'y a aucun moyen de spécifier des en-têtes lors de l'ouverture d'une connexion Websocket dans le navigateur, ce qui me ferait croire qu'il est impossible d'utiliser l'authentification au porteur pour authentifier une demande de mise à niveau de socket Web. Alors - Ai-je raté quelque chose, ou est-ce vraiment impossible? Si cela est impossible, est-ce par conception, ou s'agit-il d'un oubli flagrant dans la mise en œuvre du navigateur de l'API websocket?

22
w.brian

Vous avez raison, il est impossible pour l'instant d'utiliser l'en-tête d'authentification, en raison de la conception de l'API Javascript WebSocket. Plus d'informations peuvent être trouvées dans ce fil: en-têtes HTTP dans l'API client Websockets

Cependant, le type d'authentification au porteur autorise un paramètre de requête nommé "access_token": http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html#query-param Cette méthode est compatible avec la connexion websocket.

12
Romain F.

L'API vous permet de définir exactement un en-tête, à savoir Sec-WebSocket-Protocol, c'est-à-dire le sous-protocole spécifique à l'application. Vous pouvez utiliser cet en-tête pour passer le jeton du porteur. Par exemple:

new WebSocket("ws://www.example.com/socketserver", ["access_token", "3gn11Ft0Me8lkqqW2/5uFQ="]);

Le serveur devrait accepter l'un des protocoles, donc pour l'exemple ci-dessus, vous pouvez simplement valider le jeton et répondre avec l'en-tête Sec-WebSocket-Protocol = access_token .

30
Kalle

Exemple d'authentification de base à l'aide de l'en-tête de demande http du servlet de jeton avant la connexion Websocket:

**** ws: // localhost: 8081/remoteservice/id? access_token = tokenValue ****

vérifiez que votre jeton retourne vrai si valide sinon retournez faux

configuration du point de terminaison:

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer{

    @Autowired
    RemoteServiceHandler rsHandler;

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry){
        registry.addHandler(rsHandler, "/remoteservice/{vin}").setAllowedOrigins("*").addInterceptors(new HttpHandshakeInterceptor());
    }   
}

valider le jeton avant la connexion websocket établie:

public class HttpHandshakeInterceptor implements HandshakeInterceptor{

@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,  Map attributes) throws Exception 
{
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
String token = servletRequest.getServletRequest().getHeader("access_token");
try {
            Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();

            if (claims!=null) {
                return true;
            }
        } catch (Exception e) {

            return false;
        }
        return false;
}

ignorer le point de terminaison de sécurité http

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Override 
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().anyRequest(); 
    }

}

pom.xml

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

ajoutez l'en-tête de demande dans le fichier js comme vous le souhaitez

var request = URLRequest(url: URL(string: "ws://localhost:8081/remoteservice")!)
request.timeoutInterval = 5 // Sets the timeout for the connection
request.setValue("someother protocols", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("14", forHTTPHeaderField: "Sec-WebSocket-Version")
request.setValue("chat,superchat", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("Everything is Awesome!", forHTTPHeaderField: "My-Awesome-Header")
let socket = WebSocket(request: request)
0
Murali S