Commit c97cb881c00baeddbe0267aebbfd6d5cd59b88fd

Authored by Thomas Ziemer
1 parent 0065756c

feature: REST-Login vor WebSocket-Erstellung in der HTML-Seite

src/main/java/net/ziemers/swxercise/lg/model/user/User.java
@@ -46,6 +46,11 @@ public class User extends BaseEntity { @@ -46,6 +46,11 @@ public class User extends BaseEntity {
46 this.lastname = lastname; 46 this.lastname = lastname;
47 } 47 }
48 48
  49 + @Transient
  50 + public String getFullName() {
  51 + return String.format("%s %s", getFirstname(), getLastname());
  52 + }
  53 +
49 @OneToOne(cascade = {CascadeType.ALL}) 54 @OneToOne(cascade = {CascadeType.ALL})
50 public Profile getProfile() { 55 public Profile getProfile() {
51 return profile; 56 return profile;
src/main/java/net/ziemers/swxercise/lg/user/service/SessionContext.java
1 package net.ziemers.swxercise.lg.user.service; 1 package net.ziemers.swxercise.lg.user.service;
2 2
  3 +import javax.annotation.PreDestroy;
3 import javax.enterprise.context.SessionScoped; 4 import javax.enterprise.context.SessionScoped;
4 5
5 import net.ziemers.swxercise.lg.model.user.User; 6 import net.ziemers.swxercise.lg.model.user.User;
6 7
  8 +import java.util.Collections;
  9 +import java.util.HashMap;
  10 +import java.util.Map;
  11 +
7 /** 12 /**
8 * Verwaltet den SessionContext des zurzeit angemeldeten Benutzers. 13 * Verwaltet den SessionContext des zurzeit angemeldeten Benutzers.
9 */ 14 */
@@ -12,10 +17,17 @@ public class SessionContext implements java.io.Serializable { @@ -12,10 +17,17 @@ public class SessionContext implements java.io.Serializable {
12 17
13 private static final long serialVersionUID = 8624253586553865146L; 18 private static final long serialVersionUID = 8624253586553865146L;
14 19
  20 + private static Map<String, SessionContext> sessions = Collections.synchronizedMap(new HashMap<>());
  21 +
15 private User user = null; 22 private User user = null;
16 23
17 private String sessionId = ""; 24 private String sessionId = "";
18 25
  26 + @PreDestroy
  27 + private void deinit() {
  28 + sessions.remove(getSessionId());
  29 + }
  30 +
19 public User getUser() { 31 public User getUser() {
20 return user; 32 return user;
21 } 33 }
@@ -24,29 +36,52 @@ public class SessionContext implements java.io.Serializable { @@ -24,29 +36,52 @@ public class SessionContext implements java.io.Serializable {
24 this.user = user; 36 this.user = user;
25 } 37 }
26 38
27 - public String getSessionId() { return sessionId; } 39 + private String getSessionId() { return sessionId; }
28 40
29 private void setSessionId(String sessionId) { this.sessionId = sessionId; } 41 private void setSessionId(String sessionId) { this.sessionId = sessionId; }
30 42
31 /** 43 /**
  44 + * Liefert den Session-Kontext zur übergebenen REST-Session-Id.
  45 + *
  46 + * @param restSessionId die REST-Session-Id, deren Session-Kontext ermittelt werden soll
  47 + * @return das {@link SessionContext}-Objekt des Benutzers mit der REST-Session-Id oder <code>null</code>.
  48 + */
  49 + public static SessionContext getInstanceByRestSessionId(final String restSessionId) {
  50 + return sessions.get(restSessionId);
  51 + }
  52 +
  53 + /**
32 * Meldet einen Benutzer in diesem Session-Kontext an. 54 * Meldet einen Benutzer in diesem Session-Kontext an.
33 * 55 *
34 * @param user das {@link User}-Objekt des Benutzers dieses Session-Kontexts 56 * @param user das {@link User}-Objekt des Benutzers dieses Session-Kontexts
35 * @param sessionId die Session-Id dieser Benutzer-Session 57 * @param sessionId die Session-Id dieser Benutzer-Session
36 - * @return Liefert <code>true</code> zurück, wenn der Benutzer am Session-Kontext angemeldet werden konnte. 58 + * @return <code>true</code>, wenn der Benutzer erfolgreich am Session-Kontext angemeldet werden konnte.
37 */ 59 */
38 public boolean login(final User user, final String sessionId) { 60 public boolean login(final User user, final String sessionId) {
39 if (getUser() == null) { 61 if (getUser() == null) {
40 setUser(user); 62 setUser(user);
41 setSessionId(sessionId); 63 setSessionId(sessionId);
  64 +
  65 + // wir können später von der Session-Id auf den Session-Kontext schließen
  66 + sessions.putIfAbsent(getSessionId(), this);
  67 +
42 return true; 68 return true;
43 } 69 }
44 return false; 70 return false;
45 } 71 }
46 72
  73 + /**
  74 + * Meldet einen Benutzer von diesem Session-Kontext ab.
  75 + *
  76 + * @return <code>true</code>, wenn die Abmeldung erfolgreich durchgeführt werden konnte.
  77 + */
47 public boolean logout() { 78 public boolean logout() {
48 if (getUser() != null) { 79 if (getUser() != null) {
49 setUser(null); 80 setUser(null);
  81 +
  82 + // ohne authentifizierten Benutzer interessiert uns dieser Session-Kontext nicht mehr
  83 + sessions.remove(getSessionId());
  84 +
50 return true; 85 return true;
51 } 86 }
52 return false; 87 return false;
src/main/java/net/ziemers/swxercise/ui/ws/WebSocketController.java
1 package net.ziemers.swxercise.ui.ws; 1 package net.ziemers.swxercise.ui.ws;
2 2
  3 +import net.ziemers.swxercise.lg.model.user.User;
  4 +import net.ziemers.swxercise.lg.user.service.SessionContext;
3 import org.slf4j.Logger; 5 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory; 6 import org.slf4j.LoggerFactory;
5 7
@@ -54,6 +56,8 @@ public class WebSocketController { @@ -54,6 +56,8 @@ public class WebSocketController {
54 56
55 // wir können später über die gegebene WebSocket-Session die REST-Session-Id dieses WebSockets ermitteln 57 // wir können später über die gegebene WebSocket-Session die REST-Session-Id dieses WebSockets ermitteln
56 peers.putIfAbsent(wsSession, restSessionId); 58 peers.putIfAbsent(wsSession, restSessionId);
  59 +
  60 + getUserBySession(wsSession);
57 } 61 }
58 62
59 /** 63 /**
@@ -64,11 +68,10 @@ public class WebSocketController { @@ -64,11 +68,10 @@ public class WebSocketController {
64 */ 68 */
65 @OnMessage 69 @OnMessage
66 public void onMessage(WebSocketJson json, Session wsSession) throws IOException, EncodeException { 70 public void onMessage(WebSocketJson json, Session wsSession) throws IOException, EncodeException {
67 - // die Map liefert uns zur gegebenen WebSocket-Session die REST-Session-Id zurück  
68 - String restSessionId = peers.get(wsSession); 71 + logger.info("WebSocket Message '{}' received by session id #{}", json.getMessage(), wsSession.getId());
  72 +
  73 + getUserBySession(wsSession);
69 74
70 - logger.info("WebSocket {} Message '{}' received by session id #{}",  
71 - restSessionId, json.getMessage(), wsSession.getId());  
72 try { 75 try {
73 // Wir senden die empfangene Nachricht gleich wieder zurück. Das JSON-Marshalling geschieht automatisch. 76 // Wir senden die empfangene Nachricht gleich wieder zurück. Das JSON-Marshalling geschieht automatisch.
74 wsSession.getBasicRemote().sendObject(json); 77 wsSession.getBasicRemote().sendObject(json);
@@ -99,4 +102,20 @@ public class WebSocketController { @@ -99,4 +102,20 @@ public class WebSocketController {
99 peers.remove(wsSession); 102 peers.remove(wsSession);
100 } 103 }
101 104
  105 + private User getUserBySession(final Session wsSession) {
  106 + // die Map liefert uns zur WebSocket-Session gegebenenfalls die REST-Session-Id zurück;
  107 + // und mit dieser schließen wir auf den authentifizierten REST-Benutzer
  108 + String restSessionId = WebSocketController.peers.get(wsSession);
  109 + SessionContext ctx = SessionContext.getInstanceByRestSessionId(restSessionId);
  110 +
  111 + if (ctx != null) {
  112 + User user = ctx.getUser();
  113 +
  114 + logger.info("Detected WebSocket User '{}'", user.getFullName());
  115 +
  116 + return user;
  117 + }
  118 + return null;
  119 + }
  120 +
102 } 121 }
src/main/java/net/ziemers/swxercise/ui/ws/WebSocketJson.java
@@ -23,21 +23,18 @@ public class WebSocketJson { @@ -23,21 +23,18 @@ public class WebSocketJson {
23 public static class MessageEncoder implements Encoder.Text<WebSocketJson> { 23 public static class MessageEncoder implements Encoder.Text<WebSocketJson> {
24 24
25 @Override 25 @Override
26 - public void init(EndpointConfig config) {  
27 - } 26 + public void init(EndpointConfig config) {}
28 27
29 @Override 28 @Override
30 public String encode(WebSocketJson message) throws EncodeException { 29 public String encode(WebSocketJson message) throws EncodeException {
31 return Json.createObjectBuilder() 30 return Json.createObjectBuilder()
32 - .add("username", message.getUsername())  
33 .add("message", message.getMessage()) 31 .add("message", message.getMessage())
34 .build() 32 .build()
35 .toString(); 33 .toString();
36 } 34 }
37 35
38 @Override 36 @Override
39 - public void destroy() {  
40 - } 37 + public void destroy() {}
41 38
42 } 39 }
43 40
@@ -49,8 +46,7 @@ public class WebSocketJson { @@ -49,8 +46,7 @@ public class WebSocketJson {
49 private JsonReaderFactory factory = Json.createReaderFactory(Collections.emptyMap()); 46 private JsonReaderFactory factory = Json.createReaderFactory(Collections.emptyMap());
50 47
51 @Override 48 @Override
52 - public void init(EndpointConfig config) {  
53 - } 49 + public void init(EndpointConfig config) {}
54 50
55 @Override 51 @Override
56 public WebSocketJson decode(String str) throws DecodeException { 52 public WebSocketJson decode(String str) throws DecodeException {
@@ -58,7 +54,6 @@ public class WebSocketJson { @@ -58,7 +54,6 @@ public class WebSocketJson {
58 JsonReader reader = factory.createReader(new StringReader(str)); 54 JsonReader reader = factory.createReader(new StringReader(str));
59 JsonObject json = reader.readObject(); 55 JsonObject json = reader.readObject();
60 56
61 - message.setUsername(json.getString("username"));  
62 message.setMessage(json.getString("message")); 57 message.setMessage(json.getString("message"));
63 58
64 return message; 59 return message;
@@ -70,28 +65,17 @@ public class WebSocketJson { @@ -70,28 +65,17 @@ public class WebSocketJson {
70 } 65 }
71 66
72 @Override 67 @Override
73 - public void destroy() {  
74 - } 68 + public void destroy() {}
75 69
76 } 70 }
77 71
78 /* 72 /*
79 * Payload der JSON-Nachricht 73 * Payload der JSON-Nachricht
80 */ 74 */
81 - private String username;  
82 -  
83 private String message; 75 private String message;
84 76
85 private WebSocketJson() {} 77 private WebSocketJson() {}
86 78
87 - public String getUsername() {  
88 - return username;  
89 - }  
90 -  
91 - private void setUsername(String username) {  
92 - this.username = username;  
93 - }  
94 -  
95 public String getMessage() { 79 public String getMessage() {
96 return message; 80 return message;
97 } 81 }
src/main/webapp/websockets.html
@@ -7,45 +7,64 @@ @@ -7,45 +7,64 @@
7 7
8 <body> 8 <body>
9 <script> 9 <script>
10 - // sei "4711" die in einer vorangegangenen REST-Authentifizierung ermittelte "restSessionId"  
11 - var restSessionId = 4711; 10 + // Anmelden und REST-Session-Id erhalten
  11 + var restUrl = "http://localhost:8080/swxercise/rest/v1/user/login";
  12 + var method = "POST";
  13 + var jsObject = { "username": "admin", "password": "admin" };
  14 + var xmlHttpRequest = new XMLHttpRequest();
12 15
13 - var url = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint/" + restSessionId;  
14 - var webSocket = new WebSocket(url); 16 + xmlHttpRequest.open(method, restUrl);
  17 + xmlHttpRequest.setRequestHeader("Content-type", "application/json");
  18 + xmlHttpRequest.onreadystatechange = function() {
  19 + if (this.readyState === 4 && this.status === 200) {
  20 + var jsResponse = JSON.parse(this.responseText);
15 21
16 - // Callback-Methoden für die WebSocket-Kommunikation  
17 - webSocket.onopen = function(e) { onWebSocketOpen(e) };  
18 - webSocket.onclose = function(e) { onWebSocketClose(e) };  
19 - webSocket.onmessage = function(e) { onWebSocketMessage(e) };  
20 - webSocket.onerror = function(e) { onWebSocketError(e) }; 22 + establishWebSocket(jsResponse.message);
21 23
22 - function onWebSocketOpen(e) {  
23 - console.log("WebSocket has been opened.");  
24 - } 24 + console.log("REST-Session-Id is '" + jsResponse.message + "'.");
  25 + }
  26 + };
  27 + xmlHttpRequest.send(JSON.stringify(jsObject));
25 28
26 - function onWebSocketClose(e) {  
27 - console.log("WebSocket has been closed.");  
28 - } 29 + // WebSocket-Verbindung etablieren
  30 + var webSocket;
29 31
30 - function onWebSocketMessage(e) {  
31 - // JSON-String in ein JavaScript-Objekt konvertieren  
32 - var json = JSON.parse(e.data); 32 + function establishWebSocket(restSessionId) {
  33 + var wsUrl = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint/" + restSessionId;
33 34
34 - console.log("WebSocket Message '" + json.message + "' has been received.");  
35 - } 35 + webSocket = new WebSocket(wsUrl);
  36 +
  37 + // Callback-Methoden für die WebSocket-Kommunikation
  38 + webSocket.onopen = function(e) { onWebSocketOpen(e) };
  39 + webSocket.onclose = function(e) { onWebSocketClose(e) };
  40 + webSocket.onmessage = function(e) { onWebSocketMessage(e) };
  41 + webSocket.onerror = function(e) { onWebSocketError(e) };
  42 +
  43 + function onWebSocketOpen(e) {
  44 + console.log("WebSocket has been opened.");
  45 + }
36 46
37 - function onWebSocketError(e) {  
38 - alert("WebSocket Error " + e + " has been thrown!"); 47 + function onWebSocketClose(e) {
  48 + console.log("WebSocket has been closed.");
  49 + }
  50 +
  51 + function onWebSocketMessage(e) {
  52 + // JSON-String in ein JavaScript-Objekt konvertieren
  53 + var json = JSON.parse(e.data);
  54 +
  55 + console.log("WebSocket Message '" + json.message + "' has been received.");
  56 + }
  57 +
  58 + function onWebSocketError(e) {
  59 + alert("WebSocket Error " + e + " has been thrown!");
  60 + }
39 } 61 }
40 62
41 function sendWebSocketMessage() { 63 function sendWebSocketMessage() {
42 - var json = {  
43 - "username": "admin",  
44 - "message": "Hello World!"  
45 - } 64 + var jsonPayload = { "message": "Hello World!" };
46 65
47 // JavaScript-Objekt in einen JSON-String konvertieren 66 // JavaScript-Objekt in einen JSON-String konvertieren
48 - webSocket.send(JSON.stringify(json)); 67 + webSocket.send(JSON.stringify(jsonPayload));
49 68
50 console.log("Tried to send WebSocket Message."); 69 console.log("Tried to send WebSocket Message.");
51 } 70 }