* BAEL-1973

* Modified CSS Background

* removed unnecessary comment
This commit is contained in:
Adam InTae Gerard 2018-09-04 19:39:00 -07:00 committed by KevinGilmore
parent 8b805cad04
commit a42dfbcf12
27 changed files with 496 additions and 245 deletions

View File

@ -1,2 +1,3 @@
### Relevant Articles: ### Relevant Articles:
- [Intro to Security and WebSockets](http://www.baeldung.com/spring-security-websockets) - [Intro to Security and WebSockets](http://www.baeldung.com/spring-security-websockets)
- [Spring WebSockets: Specific User Chat](http://www.baeldung.com/spring-websocket-specific-user-chat)

View File

@ -11,9 +11,9 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-spring-5</artifactId> <artifactId>parent-spring-4</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-spring-5</relativePath> <relativePath>../parent-spring-4</relativePath>
</parent> </parent>
<dependencies> <dependencies>
@ -177,9 +177,11 @@
<properties> <properties>
<hibernate-core.version>5.2.10.Final</hibernate-core.version> <hibernate-core.version>5.2.10.Final</hibernate-core.version>
<spring-security.version>4.2.3.RELEASE</spring-security.version>
<spring-data-jpa.version>1.11.3.RELEASE</spring-data-jpa.version> <spring-data-jpa.version>1.11.3.RELEASE</spring-data-jpa.version>
<h2database.version>1.4.196</h2database.version> <h2database.version>1.4.196</h2database.version>
<logback-classic.version>1.2.3</logback-classic.version> <logback-classic.version>1.2.3</logback-classic.version>
<jackson.version>2.8.7</jackson.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,8 @@
package com.baeldung.springsecuredsockets;
public class Constants {
public static final String SECURED_CHAT_HISTORY = "/secured/history";
public static final String SECURED_CHAT = "/secured/chat";
public static final String SECURED_CHAT_ROOM = "/secured/room";
public static final String SECURED_CHAT_SPECIFIC_USER = "/secured/user/queue/specific-user";
}

View File

@ -9,7 +9,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.resource.PathResourceResolver; import org.springframework.web.servlet.resource.PathResourceResolver;
import org.springframework.web.servlet.view.JstlView; import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver; import org.springframework.web.servlet.view.UrlBasedViewResolver;
@ -20,7 +20,7 @@ import java.sql.SQLException;
@EnableJpaRepositories @EnableJpaRepositories
@ComponentScan("com.baeldung.springsecuredsockets") @ComponentScan("com.baeldung.springsecuredsockets")
@Import({ SecurityConfig.class, DataStoreConfig.class, SocketBrokerConfig.class, SocketSecurityConfig.class }) @Import({ SecurityConfig.class, DataStoreConfig.class, SocketBrokerConfig.class, SocketSecurityConfig.class })
public class AppConfig implements WebMvcConfigurer { public class AppConfig extends WebMvcConfigurerAdapter {
public void addViewControllers(ViewControllerRegistry registry) { public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index"); registry.addViewController("/").setViewName("index");

View File

@ -88,7 +88,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.authorizeRequests() .authorizeRequests()
.antMatchers("/", "/index", "/authenticate") .antMatchers("/", "/index", "/authenticate")
.permitAll() .permitAll()
.antMatchers("/secured/**/**", "/secured/socket", "/secured/success") .antMatchers("/secured/**/**", "/secured/**/**/**", "/secured/socket", "/secured/success")
.authenticated() .authenticated()
.anyRequest().authenticated() .anyRequest().authenticated()
.and() .and()

View File

@ -1,27 +1,33 @@
package com.baeldung.springsecuredsockets.config; package com.baeldung.springsecuredsockets.config;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_HISTORY;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_ROOM;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_SPECIFIC_USER;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration @Configuration
@EnableWebSocketMessageBroker @EnableWebSocketMessageBroker
@ComponentScan("com.baeldung.springsecuredsockets.controllers") @ComponentScan("com.baeldung.springsecuredsockets.controllers")
public class SocketBrokerConfig implements WebSocketMessageBrokerConfigurer { public class SocketBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override @Override
public void configureMessageBroker(MessageBrokerRegistry config) { public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/secured/history"); config.enableSimpleBroker(SECURED_CHAT_HISTORY, SECURED_CHAT_SPECIFIC_USER);
config.setApplicationDestinationPrefixes("/spring-security-mvc-socket"); config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
config.setUserDestinationPrefix("/secured/user");
} }
@Override @Override
public void registerStompEndpoints(StompEndpointRegistry registry) { public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/secured/chat").withSockJS(); registry.addEndpoint(SECURED_CHAT_ROOM).withSockJS();
registry.addEndpoint(SECURED_CHAT).withSockJS();
} }
} }

View File

@ -15,7 +15,7 @@ public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBroker
@Override @Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages messages
.simpDestMatchers("/secured/**").authenticated() .simpDestMatchers("/secured/**", "/secured/**/**").authenticated()
.anyMessage().authenticated(); .anyMessage().authenticated();
} }
} }

View File

@ -1,11 +1,19 @@
package com.baeldung.springsecuredsockets.controllers; package com.baeldung.springsecuredsockets.controllers;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_HISTORY;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_ROOM;
import static com.baeldung.springsecuredsockets.Constants.SECURED_CHAT_SPECIFIC_USER;
import com.baeldung.springsecuredsockets.transfer.socket.Message; import com.baeldung.springsecuredsockets.transfer.socket.Message;
import com.baeldung.springsecuredsockets.transfer.socket.OutputMessage; import com.baeldung.springsecuredsockets.transfer.socket.OutputMessage;
import java.security.Principal;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
@ -19,10 +27,19 @@ public class SocketController {
private SimpMessagingTemplate simpMessagingTemplate; private SimpMessagingTemplate simpMessagingTemplate;
private static final Logger log = LoggerFactory.getLogger(SocketController.class); private static final Logger log = LoggerFactory.getLogger(SocketController.class);
@MessageMapping("/secured/chat") @MessageMapping(SECURED_CHAT)
@SendTo("/secured/history") @SendTo(SECURED_CHAT_HISTORY)
public OutputMessage send(Message msg) throws Exception { public OutputMessage sendAll(Message msg) throws Exception {
OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date())); OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date()));
return out; return out;
} }
/**
* Example of sending message to specific user using 'convertAndSendToUser()' and '/queue'
*/
@MessageMapping(SECURED_CHAT_ROOM)
public void sendSpecific(@Payload Message msg, Principal user, @Header("simpSessionId") String sessionId) throws Exception {
OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date()));
simpMessagingTemplate.convertAndSendToUser(msg.getTo(), SECURED_CHAT_SPECIFIC_USER, out);
}
} }

View File

@ -3,6 +3,7 @@ package com.baeldung.springsecuredsockets.transfer.socket;
public class Message { public class Message {
private String from; private String from;
private String to;
private String text; private String text;
public String getFrom() { public String getFrom() {
@ -11,6 +12,13 @@ public class Message {
public void setFrom(String from) { public void setFrom(String from) {
this.from = from; this.from = from;
} }
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getText() { public String getText() {
return text; return text;
} }

View File

@ -4,15 +4,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Spring Secured Sockets</title> <title>Spring Secured Sockets</title>
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet"> <link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
<link href="<c:url value="/resources/styles/denied.css"/>" rel="stylesheet">
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script> <script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
</head> </head>
<body> <body>
<main>
<div class="wrapper">
<h1>ACCESS DENIED!</h1> <h1>ACCESS DENIED!</h1>
<br/>
<br/>
<a href="${pageContext.request.contextPath}/login">Click to login.</a> <a href="${pageContext.request.contextPath}/login">Click to login.</a>
</div>
</main>
</body> </body>
</html> </html>

View File

@ -4,9 +4,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html ng-app='angularApp'> <html ng-app='angularApp'>
<head> <head>
<title>Spring Secured Sockets</title> <title>Spring Secured Sockets</title>
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet"> <link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
<link href="<c:url value="/resources/styles/index.css"/>" rel="stylesheet">
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script> <script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script> <script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script> <script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
@ -14,17 +17,19 @@
<script src="<c:url value="/resources/scripts/app.js" />"></script> <script src="<c:url value="/resources/scripts/app.js" />"></script>
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script> <script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script> <script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
</head> </head>
<body ng-controller="indexController"> <body ng-controller="indexController">
<main>
<div class="wrapper">
<h1>Welcome!</h1> <h1>Welcome!</h1>
<br />
<span>{{greeting}}</span> <span>{{greeting}}</span>
<br />
<br />
<a href="${pageContext.request.contextPath}/login">Click to login.</a> <a href="${pageContext.request.contextPath}/login">Click to login.</a>
</div>
</main>
</body> </body>
</html> </html>

View File

@ -4,9 +4,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html ng-app='angularApp'> <html ng-app='angularApp'>
<head> <head>
<title>Spring Secured Sockets</title> <title>Spring Secured Sockets</title>
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet"> <link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
<link href="<c:url value="/resources/styles/login.css"/>" rel="stylesheet">
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script> <script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script> <script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script> <script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
@ -14,24 +17,26 @@
<script src="<c:url value="/resources/scripts/app.js" />"></script> <script src="<c:url value="/resources/scripts/app.js" />"></script>
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script> <script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script> <script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
</head> </head>
<body ng-controller="loginController">
<body>
<c:set var="context" scope="session" value="${pageContext.request.contextPath}"/> <c:set var="context" scope="session" value="${pageContext.request.contextPath}"/>
<main>
<div class="wrapper">
<!-- Must match the endpoint specified in security config --> <!-- Must match the endpoint specified in security config -->
<h1>JSP Login Form</h1><br/> <h1>JSP Login Form</h1>
<form name='f' action="authenticate" method='POST'> <form name='f' action="authenticate" method='POST'>
<table> <table>
<tr> <tr>
<td>User:</td> <td>User:</td>
<td><input type="text" name="username"/></td> <td><input type="text" name="username" placeholder="k everyperson"/></td>
</tr> </tr>
<tr> <tr>
<td>Password:</td> <td>Password:</td>
<td><input type="password" name="password"/></td> <td><input type="password" name="password" placeholder="1234abcd"/></td>
</tr> </tr>
<tr> <tr>
<td><input name="submit" type="submit" value="submit"/></td> <td><input name="submit" type="submit" value="submit"/></td>
@ -39,7 +44,10 @@
</table> </table>
</form> </form>
</div>
</main>
<!-- CSRF Token --> <!-- CSRF Token -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</body> </body>
</html> </html>

View File

@ -4,9 +4,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html ng-app='angularApp'> <html ng-app='angularApp'>
<head> <head>
<title>Spring Secured Sockets</title> <title>Spring Secured Sockets</title>
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet"> <link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
<link href="<c:url value="/resources/styles/socket.css"/>" rel="stylesheet">
<script src="<c:url value="/resources/vendor/sockjs/sockjs.min.js" />"></script> <script src="<c:url value="/resources/vendor/sockjs/sockjs.min.js" />"></script>
<script src="<c:url value="/resources/vendor/stomp/stomp.min.js" />"></script> <script src="<c:url value="/resources/vendor/stomp/stomp.min.js" />"></script>
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script> <script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
@ -16,36 +19,41 @@
<script src="<c:url value="/resources/scripts/app.js" />"></script> <script src="<c:url value="/resources/scripts/app.js" />"></script>
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script> <script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script> <script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
</head> </head>
<body ng-controller="socketController"> <body ng-controller="socketController">
<h1>Socket Chat</h1>
<c:set var="context" scope="session" value="${pageContext.request.contextPath}"/> <c:set var="context" scope="session" value="${pageContext.request.contextPath}"/>
<div> <main>
<div> <div class="wrapper">
<input type="text" id="from" placeholder="Choose a nickname"/> <h1>Socket Chat</h1>
<div id="all">
<h3>(Chat With Everyone)</h3>
<input type="text" id="from" placeholder="Choose Your Username"/>
<button id="connectAll" ng-click="connectAll('${context}');">Connect All</button>
<button id="subscribeAll" ng-click="subscribeAll();">Subscribe All</button>
</div> </div>
<br/> <div id="specific">
<div> <h3>(Chat With A Specific User)</h3>
<button id="connect" ng-click="connect('${context}');">Connect</button> <input type="text" id="to" placeholder="Choose a Recipient"/>
<button id="subscribe" ng-click="subscribe();">Subscribe</button> <button id="connectSpecific" ng-click="connectSpecific('${context}');">Connect Specific</button>
<button id="disconnect" disabled="disabled" ng-click="disconnect();">Disconnect</button> <button id="subscribeSpecific" ng-click="subscribeSpecific();">Subscribe Specific</button>
</div> </div>
<br/>
<div id="conversationDiv"> <div id="conversationDiv">
<h3>(Send and See Messages)</h3>
<input type="text" id="text" placeholder="Write a message..."/> <input type="text" id="text" placeholder="Write a message..."/>
<button id="sendMessage" ng-click="sendMessage('${context}');">Send</button> <button id="sendMessage" ng-click="sendMessage('${context}');">Send</button>
<p id="response"></p> <div id="response"></div>
<button id="disconnect" disabled="disabled" ng-click="disconnect();">Disconnect</button>
</div> </div>
</div>
<a href="${context}/secured/success">Click to go back!</a> <a href="${context}/secured/success">Click to go back!</a>
<a href="${context}/">Click to start over (you will still be authenticated)!</a> <a href="${context}/">Click to start over (you will still be authenticated)!</a>
</div>
</main>
<!-- CSRF Token --> <!-- CSRF Token -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</body> </body>
</html> </html>

View File

@ -4,9 +4,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html ng-app='angularApp'> <html ng-app='angularApp'>
<head> <head>
<title>Spring Secured Sockets</title> <title>Spring Secured Sockets</title>
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet"> <link href="<c:url value="/resources/styles/app.css"/>" rel="stylesheet">
<link href="<c:url value="/resources/styles/success.css"/>" rel="stylesheet">
<script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script> <script src="<c:url value="/resources/vendor/jquery/jquery.min.js" />"></script>
<script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script> <script src="<c:url value="/resources/vendor/angular/angular.min.js" />"></script>
<script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script> <script src="<c:url value="/resources/vendor/angular/angular-route.min.js" />"></script>
@ -14,17 +17,19 @@
<script src="<c:url value="/resources/scripts/app.js" />"></script> <script src="<c:url value="/resources/scripts/app.js" />"></script>
<script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script> <script src="<c:url value="/resources/scripts/services/SocketService.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/indexController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/loginController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/socketController.js" />"></script>
<script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script> <script src="<c:url value="/resources/scripts/controllers/successController.js" />"></script>
<script src="<c:url value="/resources/scripts/routes/router.js" />"></script> <script src="<c:url value="/resources/scripts/routes/router.js" />"></script>
</head> </head>
<body ng-controller="successController">
<h1>Congrats! You've logged in.</h1>
<body ng-controller="successController">
<main>
<div class="wrapper">
<h1>Congrats! You've logged in.</h1>
<a href="${pageContext.request.contextPath}/secured/socket">Click to chat!</a> <a href="${pageContext.request.contextPath}/secured/socket">Click to chat!</a>
<a href="${pageContext.request.contextPath}/">Click to start over (you will still be authenticated)!</a> <a href="${pageContext.request.contextPath}/">Click to start over (you will still be authenticated)!</a>
</div>
</main>
<!-- CSRF Token --> <!-- CSRF Token -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</body> </body>

View File

@ -2,6 +2,7 @@
angularApp angularApp
.controller('indexController', function ($scope) { .controller('indexController', function ($scope) {
$scope.greeting = ''; $scope.greeting = '';
$scope.initialize = function () { $scope.initialize = function () {

View File

@ -1,6 +0,0 @@
'use strict';
angularApp
.controller('loginController', function ($scope) {
});

View File

@ -3,35 +3,50 @@
angularApp angularApp
.controller('socketController', function ($scope, SocketService) { .controller('socketController', function ($scope, SocketService) {
$scope.stompClient = null; /**
$scope.sendEndpoint = '/secured/chat'; * URL mapping endpoints.
$scope.subscribeEndpoint = '/secured/history'; */
$scope.elems = {
connect: 'connect', var SECURED_CHAT = '/secured/chat';
var SECURED_CHAT_HISTORY = '/secured/history';
var SECURED_CHAT_ROOM = '/secured/room';
var SECURED_CHAT_SPECIFIC_USER = '/secured/user/queue/specific-user';
var opts = {
from: 'from', from: 'from',
to: 'to',
text: 'text', text: 'text',
disconnect: 'disconnect', disconnect: 'disconnect',
conversationDiv: 'conversationDiv', conversationDiv: 'conversationDiv',
response: 'response' response: 'response'
}; };
$scope.connect = function (context) { $scope.sendEndpoint = '';
$scope.sendEndpoint = '/secured/chat'; $scope.stompClient = null;
$scope.sendEndpoint = context + $scope.sendEndpoint ;
$scope.stompClient = SocketService.connect($scope.sendEndpoint, $scope.elems); /**
* Broadcast to All Users.
*/
$scope.connectAll = function (context) {
$scope.sendEndpoint = context + SECURED_CHAT;
$scope.stompClient = SocketService.connect($scope.sendEndpoint , opts, true);
}; };
$scope.subscribe = function () { $scope.subscribeAll = function () { SocketService.subscribeToAll($scope.stompClient, SECURED_CHAT_HISTORY, opts); };
$scope.stompClient.subscribe($scope.subscribeEndpoint, function (msgOut) {
SocketService.messageOut(JSON.parse(msgOut.body), $scope.elems); /**
}); * Broadcast to Specific User.
}; */
$scope.disconnect = function () { $scope.connectSpecific = function (context) {
SocketService.disconnect($scope.elems, $scope.stompClient); $scope.sendEndpoint = context + SECURED_CHAT_ROOM;
}; $scope.stompClient = SocketService.connect(context + SECURED_CHAT_ROOM, opts, false);
};
$scope.sendMessage = function () {
SocketService.sendMessage( $scope.elems, $scope.stompClient, $scope.sendEndpoint); $scope.subscribeSpecific = function () { SocketService.subscribeToSpecific($scope.stompClient, SECURED_CHAT_SPECIFIC_USER, opts); };
};
$scope.disconnect = function () { SocketService.disconnect(opts, $scope.stompClient); };
$scope.sendMessage = function () { SocketService.sendMessage(opts, $scope.stompClient, $scope.sendEndpoint); };
}); });

View File

@ -2,7 +2,6 @@
angularApp angularApp
.controller('successController', function ($scope) { .controller('successController', function ($scope) {
$scope.successMsg = ''; $scope.successMsg = '';
$scope.initialize = function () { $scope.initialize = function () {

View File

@ -6,9 +6,6 @@ angularApp
.when('/index', { .when('/index', {
controller: 'indexController' controller: 'indexController'
}) })
.when('/login', {
controller: 'loginController'
})
.when('/sockets', { .when('/sockets', {
controller: 'socketController' controller: 'socketController'
}) })

View File

@ -1,45 +1,98 @@
'use strict'; 'use strict';
function SocketService() { var idHelper = function (context) {
var that = this,
idHelper = function(context) {
return document.getElementById(context); return document.getElementById(context);
}; };
that.setConnected = function (elems, connected) { function SocketService() {
idHelper(elems.connect).disabled = connected;
idHelper(elems.disconnect).disabled = !connected; var that = this;
idHelper(elems.conversationDiv).style.visibility = connected ? 'visible' : 'hidden';
idHelper(elems.response).innerHTML = ''; that.sessionId = '';
/**
* Generic methods.
*/
that.setConnected = function (opts, connected) {
idHelper('connectAll').disabled = connected;
idHelper('connectSpecific').disabled = connected;
idHelper(opts.disconnect).disabled = !connected;
idHelper(opts.response).innerHTML = '';
idHelper('subscribeAll').disabled = !connected;
idHelper('subscribeSpecific').disabled = !connected;
}; };
that.connect = function (endpoint, elems) { that.connect = function (endpoint, opts, isBroadcastAll) {
var socket = new SockJS(endpoint), stompClient = Stomp.over(socket); var socket = new SockJS(endpoint), stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) { stompClient.connect({}, function (frame) {
that.setConnected(elems, true); that.setConnected(opts, true);
if (!isBroadcastAll) {
var url = stompClient.ws._transport.url;
console.log(stompClient.ws._transport.url);
url = url.replace("ws://localhost:8080/spring-security-mvc-socket/secured/room/", "");
url = url.replace("/websocket", "");
url = url.replace(/^[0-9]+\//, "");
console.log("Your current session is: " + url);
that.sessionId = url;
}
}); });
return stompClient; return stompClient;
}; };
that.disconnect = function (elems, stompClient) { that.disconnect = function (opts, stompClient) {
if (stompClient !== null && stompClient !== undefined) stompClient.disconnect(); if (stompClient !== null && stompClient !== undefined) { stompClient.disconnect(); }
that.setConnected(elems, false); that.setConnected(opts, false);
}; };
that.sendMessage = function (elems, stompClient, endpoint) { that.sendMessage = function (opts, stompClient, endpoint) {
stompClient.send(endpoint, {}, var to = idHelper(opts.to).value;
JSON.stringify({ var from = idHelper(opts.from).value;
'from': idHelper(elems.from).value,
'text': idHelper(elems.text).value var msg = {
})); 'from': (from === undefined || from === null ) ? to : from,
'to': (to === undefined || to === null ) ? "ALL" : to,
'text': idHelper(opts.text).value
}; };
that.messageOut = function (msg, elems) { console.log(JSON.stringify(msg));
var r = idHelper(elems.response), p = document.createElement('p'); stompClient.send(endpoint, {}, JSON.stringify(msg));
};
that.messageOut = function (msg, opts) {
var r = idHelper(opts.response), p = document.createElement('p');
p.style.wordWrap = 'break-word'; p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(msg.from + ': ' + msg.text + ' (' + msg.time + ')')); p.appendChild(document.createTextNode(msg.from + ': ' + msg.text + ' (' + msg.time + ')'));
r.appendChild(p); r.appendChild(p);
}; };
/**
* Broadcast to All Users.
*/
that.subscribeToAll = function(client, url, opts) {
idHelper('subscribeAll').disabled = true;
idHelper('subscribeSpecific').disabled = true;
client.subscribe(url, function (msgOut) {
that.messageOut(JSON.parse(msgOut.body), opts);
});
};
/**
* Broadcast to Specific User.
*/
that.subscribeToSpecific = function(client, url, opts) {
idHelper('subscribeAll').disabled = true;
idHelper('subscribeSpecific').disabled = true;
client.subscribe(url + "-user" + that.sessionId, function (msgOut) {
that.messageOut(JSON.parse(msgOut.body), opts);
});
};
} }
angularApp angularApp

View File

@ -0,0 +1,70 @@
@import url('https://fonts.googleapis.com/css?family=Poiret+One');
html, body, main {
padding: 0;
margin: 0;
position: absolute;
height: 100%;
width: 100%;
color: white;
font-family: 'Poiret One', sans-serif;
opacity:.95;
}
main {
background-size: cover;
}
main > div.wrapper {
position: relative;
left: 15%;
top: 15%;
width: 40%;
}
h1 {
text-transform: uppercase;
font-size: 48px;
letter-spacing: 2px;
}
span, a {
font-size: 24px;
letter-spacing: 1px;
}
a {
text-decoration: none;
color: white;
}
a:hover {
color: lightgray;
}
input {
width: 225px;
background: none !important;
border-radius: 25px;
background-color: #fff;
color: white;
outline: none;
margin-left: 2px;
padding-left: 25px;
padding-bottom: 9px;
padding-top: 9px;
}
button {
width: 100px;
align-content: center;
text-align: center;
background: transparent;
border-radius: 25px;
padding: 6px;
color: white;
}
button:hover {
opacity: .6;
}

View File

@ -0,0 +1,3 @@
main {
background-color: black;
}

View File

@ -0,0 +1,7 @@
main {
background-color: black;
}
span, a {
top: 175px;
}

View File

@ -0,0 +1,17 @@
main {
background-color: black;
}
input[type="submit"] {
width: 100px;
align-content: center;
text-align: center;
background: transparent;
border-radius: 25px;
padding: 6px;
color: white;
}
input[type="submit"]:hover {
opacity:.6;
}

View File

@ -0,0 +1,19 @@
main {
background-color: black;
}
div#all, div#specific, div#conversationDiv {
border: 1px solid white;
border-radius: 25px;
padding: 15px;
margin: 15px
}
button[disabled=true] {
color: lightgray;
border: 1px solid lightgray;
}
button[disabled=true]:hover {
opacity: 1;
}

View File

@ -0,0 +1,3 @@
main {
background-color: black;
}