I have a trouble with CORS configuration. I've followed few tutorials, videos on YT and I was looking for help here, on StackOverflow - but nothing helps me.
I have two backend projects (first one - Spring Boot 1.5.9 with OAuth2 and JWT, second one - Spring Boot 2.0.0 M7 with Spring Security 5 basic authentication) and my friend uses React for frontend. In both I have the same problem - when we want to login, server responses with 401 HTTP status and following message:
Failed to load http://localhost:8080/oauth/token: Response for preflight has invalid HTTP status code 401
Case 1 (Spring Boot 1.5.9 OAuth2 JWT)
In this project I have
SecurityConfig class that extends WebSecurityConfigurerAdapter
My implementation of AuthorizationServerConfigurerAdapter
And implementation of ResourceServerConfig
My ResourceServerConfig class looks like this:
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCES_IDS = "ResourceId";
private static final String SECURITY_REALM = "Spring Boot Realm";
private final TokenStore tokenStore;
#Autowired
public ResourceServerConfig(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCES_IDS)
.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(REGISTER_USER + "/**").permitAll()
.antMatchers(HttpMethod.GET, GEOTAGS_PATH + "/**").permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.httpBasic()
.realmName(SECURITY_REALM)
.and()
.csrf().disable().cors();
}
}
AuthorizationServerConfig:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final TokenStore tokenStore;
private final JwtAccessTokenConverter accessTokenConverter;
private final AuthenticationManager authenticationManager;
private final DataSource dataSource;
#Autowired
public AuthorizationServerConfig(TokenStore tokenStore,
JwtAccessTokenConverter accessTokenConverter,
AuthenticationManager authenticationManager,
#Qualifier("customDatasource") DataSource dataSource) {
this.tokenStore = tokenStore;
this.accessTokenConverter = accessTokenConverter;
this.authenticationManager = authenticationManager;
this.dataSource = dataSource;
}
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer
.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
final TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
enhancerChain.setTokenEnhancers(Collections.singletonList(accessTokenConverter));
endpoints.tokenStore(tokenStore)
.accessTokenConverter(accessTokenConverter)
.tokenEnhancer(enhancerChain)
.authenticationManager(authenticationManager);
}
}
And finally SecurityConfig:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String SIGNING_KEY = "Gz73RSOADKDFXzONqg3q";
private UserDetailsService customUserDetailsService;
private DataSource dataSource;
#Autowired
public void setCustomUserDetailsService(UserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
}
#Autowired
public void setDataSource(#Qualifier("customDatasource") DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(SIGNING_KEY);
return converter;
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
As you can see I use CorsConfigurationSource Bean but when we run javascript code which is in different Origin:
fetch('http://localhost:8080/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${window.btoa('eTaxiClientId:secret')}`
},
body: `username=${encodeURIComponent('Admin')}&password=${encodeURIComponent('pass')}&grant_type=password`
});
Server response with message that I described on the beginning.
I have also tried use my implementation of WebMvcConfigurerAdapter with overridden addCorsMappings method, I tried to permitAll HttpMethod.OPTIONS but browser always sends OPTIONS request witch is matched with 401 code.
Case 2 (Spring Boot 2)
In this project I tried to use basic Spring Security authorization system - without OAuth2 and JWT. And my configuration is:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final MyUserDetailsService userDetailsService;
private final DataSource dataSource;
public SecurityConfig(MyUserDetailsService userDetailsService,
#Qualifier("customDatasource") DataSource dataSource) {
this.userDetailsService = userDetailsService;
this.dataSource = dataSource;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.servletApi().and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/api/1").hasAuthority("USER")
.antMatchers("/api/2").hasAuthority("ADMIN")
.antMatchers("/api/3").hasAuthority("GUEST")
.and()
.anonymous().principal("guest").authorities("GUEST")
.and()
.formLogin().permitAll()
.successHandler(new CustomAuthenticationSuccessHandler())
.failureHandler(new CustomAuthenticationFailureHandler())
.and()
.logout()
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.and()
.rememberMe().rememberMeParameter("remember-me").tokenRepository(tokenRepository())
.and()
.headers()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.and()
.cors()
.and()
.csrf().disable();
// .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
public PersistentTokenRepository tokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl = new JdbcTokenRepositoryImpl();
jdbcTokenRepositoryImpl.setDataSource(dataSource);
return jdbcTokenRepositoryImpl;
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedHeaders(Collections.singletonList("*"));
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
And in this case when we run following code in JavaScript application:
const body = `username=${encodeURIComponent('admin')}&password=${encodeURIComponent('pass')}`;
const hashedCredentials = btoa('admin:pass');
return axios.post(`${process.env.REACT_APP_API_URL}/login`, body, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
// test oauth credentials
Authorization: `Basic ${hashedCredentials}`
}
})
.then(() => {
localStorage.setItem('user', hashedCredentials);
})
.then(() => {
const userCredentials = localStorage.getItem('user');
return axios.get(`${process.env.REACT_APP_API_URL}/api/2`, null, {
headers: {
Authorization: `Basic ${userCredentials}`
}
});
}).then(res => console.log(res)).catch(err => console.log(err));
OPTIONS request passes and we have status 200 response but as you can see we tried to redirect user to end point that is protected. But instead of displaying message on the screen, Spring Security redirects as to login page..
Summary
Have someone had such problem? Does someone see what we are doing wrong ? Why do we have problem in both projects? Is better (and safer) approach for user authentication?
I hope I haven't forgotten to describe something and I am looking forward for response. Cheers !
Related
This question already has an answer here:
CORS Error: “requests are only supported for protocol schemes: http…” etc
(1 answer)
Closed 1 year ago.
I have a problem with the CORS. I have the following configuration of security:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService userDetailsService;
#Autowired
private CustomJwtAuthenticationFilter customJwtAuthenticationFilter;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(HttpSecurity http) throws Exception {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
corsConfiguration.setAllowedOrigins(List.of("*"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
http.csrf().disable()
.authorizeRequests()
.antMatchers("/helloadmin").hasRole("ADMIN")
.antMatchers("/hellouser").hasAnyRole("USER","ADMIN")
.antMatchers("/techshop/web/v1/product/save").hasRole("ADMIN")
.antMatchers("techshop/web/v1/product").hasAnyRole("USER", "ADMIN")
.antMatchers("techshop/web/v1/product/{id}").hasRole("ADMIN")
.antMatchers("/authenticate").permitAll().anyRequest().authenticated()
.and().exceptionHandling()
//if any exception occurs call this
.authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//Add a filter to validate the tokens with every request
http.addFilterBefore((Filter) customJwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);
}
}
And I have the following controllers:
#RestController
#RequestMapping(value = "")
public class AuthenticationController {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtUtil jwtUtil;
#PostMapping(path = "/authenticate", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> createAuthenticationToken(#RequestBody AuthenticationRequest request) throws Exception {
try{
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
request.getUsername(), request.getPassword()));
} catch (DisabledException e) {
throw new Exception("USER_DISABLE", e);
} catch (BadCredentialsException e){
throw new Exception("INVALID_CREDENTIALS", e);
}
final UserDetails userDetails = customUserDetailsService.loadUserByUsername(request.getUsername());
final String token = jwtUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthenticationResponse(token));
}
}
And:
#RestController
#RequestMapping("techshop/web/v1")
public class ProductController {
#Autowired
private ProductServiceI productService;
#PostMapping(value = "/product/save", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> save(#RequestBody ProductDto request){
productService.save(request);
return ResponseEntity.ok(Boolean.TRUE);
}
#GetMapping(value = "/product", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> findAll(){
return ResponseEntity.ok(productService.findAll());
}
#PutMapping(value = "/product/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> updateProduct(#PathVariable("id") int id, #RequestBody ProductDto request){
productService.update(request, id);
return ResponseEntity.ok(Boolean.TRUE);
}
#DeleteMapping(value = "/product/{id}")
public ResponseEntity<Object> deleteById(#PathVariable("id") int id){
productService.deletedById(id);
return ResponseEntity.ok(Boolean.TRUE);
}
}
When I make the following request, the browser show the CORS problem:
let datos = {
username:"admin",
password:"admin"
}
const getToken = () => {
axios({
method: 'post',
url: 'localhost:8080/test',
data: datos
});
}
getToken()
enter image description here
I've tried everything, with the #CrosOrigin ("*") annotation, with lambdas, with a Bean WebConfig that extends from corsConfigurer, but nothing works.
I appreciate if you can help me.
Please try the following:
const getToken = () => {
axios({
method: 'post',
url: 'http://localhost:8080/test',
data: datos
});
}
Server side: Spring boot + JWT Auth
Client: React app
I want to connect via websocket but whenever I try to do it I always get error in console:
WebSocket connection to 'ws://localhost:6060/ws/app/add' failed: Error during WebSocket handshake: Unexpected response code: 404
Backend:
1) Websocket configuration
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("http://localhost:6060")
.setAllowedOrigins("http://localhost:8082")
// .setAllowedOrigins("*")
.setHandshakeHandler(new DefaultHandshakeHandler(new TomcatRequestUpgradeStrategy()))
.withSockJS();
registry.addEndpoint("/add");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
2) Controller for receiving:
#Controller
public class ChatController {
#MessageMapping("/send") // FROM FRONTEND TO HERE
#SendTo("/topic/public") // FROM HERE TO FRONTEND
public ChatMessage sendMessage(#Payload ChatMessage chatMessage) {
return chatMessage;
}
#MessageMapping("/add")
#SendTo("/topic/public")
public ChatMessage addUser(#Payload ChatMessage chatMessage,
SimpMessageHeaderAccessor headerAccessor) {
// Add username in web socket session
headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
return chatMessage;
}
}
3) Security Config
package com.winterrent.winterrent.configuration;
import com.winterrent.winterrent.security.JwtAuthenticationEntryPoint;
import com.winterrent.winterrent.security.JwtAuthenticationFilter;
import com.winterrent.winterrent.service.user.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http
.cors()
.and()
.csrf()
.ignoringAntMatchers("/ws/**")
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.anyRequest()
.authenticated();
}
}
4) JWT Auth filter
package com.winterrent.winterrent.security;
import com.winterrent.winterrent.service.user.CustomUserDetailsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
/**
* JWT token got from the request, validated and based on it loads the user associated with the token and pass
* it to Spring Security
*/
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private JwtTokenProvider tokenProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
LOGGER.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
LOGGER.debug(request.getHeader("Sec-WebSocket-Protocol"));
if (Objects.nonNull(request.getHeader("Sec-WebSocket-Protocol"))) {
bearerToken = request.getHeader("Sec-WebSocket-Protocol");
return bearerToken.substring(15, bearerToken.length());
}
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
5) CORS settings
package com.winterrent.winterrent.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private final long MAX_AGE_SECS = 3600;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:6060")
.allowedOrigins("http://localhost:8082")
// .allowedOrigins("*")
.allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
.allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
"Access-Control-Request-Headers", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
.maxAge(MAX_AGE_SECS);
}
}
Client:
const wsx123 = new WebSocket('ws://localhost:6060/ws/app/add',
['Authorization', window.localStorage.getItem('accessToken')], ['Access-Control-Allow-Credentials', 'true']);
I tried many options, but really always 404...
Has anybody any idea?
Regards!
The issue was with really bad path (404 was not stupid error) -
'ws://localhost:6060/resources/ws'
Above was correct because I had resources context path set up.
I have a problem that I don't seem to figure out. I want to send a http request from my
Angular client
export class UsersService {
private baseUrl = 'http://localhost:8095/rest/users';
createUser(user: Object): Observable<Object> {
return this.http.post(`${this.baseUrl}` , user);
}
getUsers(): Observable<any> {
return this.http.get(`${this.baseUrl}/all`);
}
}
create user component.ts :
save() {
this.userService.createUser(this.user)
.subscribe(data => console.log(data), error => console.log(error));
this.user = new User();}
this is the SpringBoot backend
#RestController
#RequestMapping("/rest/users")
public class UsersResource {
private UserRepository userRepository;
public UsersResource(UserRepository userRepository) {
this.userRepository = userRepository;
}
#GetMapping("/all")
public List<Users> getAll() {
return userRepository.findAll();
}
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void create(#RequestBody Users users) {
userRepository.save(users);
}
}
when i call http://localhost:4200/users i got a clean result with all users without any problem
but when i want to add a user from here http://localhost:4200/adduser it show for me some issue
by the way iam using CORS chrome extension
i hope that someone help me for this isse.
thanks
while signing up, I am unable to get the response code and error message so can you help me?
This is My Interface
public interface SignupAPI {
#FormUrlEncoded
#POST("users")
Call<ResponseBody> createUser(
#Field("email") String email,
#Field("password") String password,
#Field("role") String role
);
}
This is Java Class
public class SignupClient {
private static final String BASE_URL = "http://74.207.233.160/api/v1/";
private static SignupClient mInstance;
private Retrofit retrofit;
private SignupClient(){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
}
public static synchronized SignupClient getmInstance(){
if (mInstance == null){
mInstance = new SignupClient();
}
return mInstance;
}
public SignupAPI getApi(){
return retrofit.create(SignupAPI.class);
}
}
This Is Signup Activity
progressBar.setVisibility(View.VISIBLE);
Call<ResponseBody> call = SignupClient.getmInstance().getApi().createUser(email, password,role);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()){
progressBar.setVisibility(View.GONE);
Toast.makeText(SignupActivity.this, "Account Sucessfully Created", Toast.LENGTH_SHORT).show();
}else {
try {
progressBar.setVisibility(View.GONE);
JSONObject jsonError = new JSONObject(response.errorBody().string());
Toast.makeText(SignupActivity.this, jsonError.getString("errors"),Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
progressBar.setVisibility(View.GONE);
e.printStackTrace();
} catch (IOException e) {
progressBar.setVisibility(View.GONE);
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(SignupActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
I am not able to get error message and also response code so please help me to get it.
Here is the Postman PostMan API
Here I have written how you can get HTTP code from both success response and error response.
#Override
public void onResponse(Call<T> call, Response<T> response) {
int statusCode = response.code();
}
#Override
public void onFailure(Call<T> call, Throwable t) {
if (new Exception(t) instanceof HttpException) {
int statusCode = ((HttpException) t).getStatusCode();
else {
// unknown error
}
}
I've started this multi chat thread alert system and I've successfully gotten multiple clients on the server, but when broadcasting the message to everyone, it only interacts with the initial client sending the message and the sever only, the other client does not receive the message.
Here are the codes I'm working with
Client 1
package popup;
import java.io.*;
import java.net.*;
import javax.swing.*;
public class ClientJFrame extends javax.swing.JFrame {
static Socket s;
static DataInputStream din;
static DataOutputStream dout;
public ClientJFrame() {
super("Client 1");
initComponents();
}
private void alertButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
String msgout = "Alert client 1\n";
dout.writeUTF(msgout);
} catch (Exception e) {
}
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ClientJFrame().setVisible(true);
}
});
try {
s = new Socket("127.0.0.1", 111);
din = new DataInputStream(s.getInputStream());
dout = new DataOutputStream(s.getOutputStream());
String msgin = "";
while (true) {
msgin = din.readUTF();
messageArea.append(msgin);
JOptionPane.showMessageDialog(null, "BITCH WE ON FIRE");
s.close();
System.exit(0);
}
} catch (Exception e) {
}
}
// Variables declaration - do not modify
private javax.swing.JButton alertButton;
private javax.swing.JScrollPane jScrollPane1;
private static javax.swing.JTextArea messageArea;
// End of variables declaration
}
Server
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class TestJFrame extends javax.swing.JFrame {
static ServerSocket listener;
static Socket s;
private static final int PORT = 111;
public TestJFrame() {
super("Main");
initComponents();
}
public static class Handler extends Thread {
private final Socket socket;
private DataInputStream in;
private DataOutputStream out;
public Handler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
in = new DataInputStream(socket.getInputStream());
messageArea.append("in\n");
out = new DataOutputStream(socket.getOutputStream());
messageArea.append("Out\n");
} catch (IOException e) {
}
while (true) {
try {
String input = in.readUTF();
messageArea.append(input);
out.writeUTF("We on Fire!!!\n");
} catch (IOException ex) {
Logger.getLogger(TestJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static void main(String args[]) throws IOException, InterruptedException {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestJFrame().setVisible(false);
createAndShowGUI();
}
});
listener = new ServerSocket(PORT);
try {
while (true) {
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}
// Variables declaration - do not modify
private javax.swing.JButton alertButton;
private javax.swing.JScrollPane jScrollPane1;
private static javax.swing.JTextArea messageArea;
// End of variables declaration
}
When a client connects to the server, add him to a list, so you always know who's connected. The same goes for when he disconnects.
When a client sends a message, process it however you want, then iterate over the list of connected clients and send them the message.
Take a look at the observer pattern, I think it will help for your project.