I can't consume microservice Spring - spring

I'm learning java Spring and I want to consume one microservice so I created a form in HTML and I try to send the user and password with axios
var helloWorld = new Vue({
el: '#vue-app',
data:
{
user: "user",
username : "",
password : ""
},
methods:
{
enviar: function()
{
axios.post('/user/login', {
user: this.username,
password: this.password
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
});
and I try to get the information
#Controller("/user")
public class UserController {
private final Log log = LogFactory.getLog(UserController.class);
#PostMapping("/login")
public boolean login(#RequestParam("user") String user, #RequestParam("password") String password)
{
log.info("user: " + user + " password: " + password);
return user.equals("hitzu") && password.equals("250693");
}
}`
But when I try to run the code I get error 404 and I try to set the URL in Postman
http://localhost:8080/user/login?user=hitzu&password=250693
but get the same error.

You are probably getting 404 because your controller thinks it should bind a View with the data it fetches.
Tell it not to bind a View essentially making it a REST endpoint and directly write into the HTTP Response Body by annotating your method with #ResponseBody.
Some further info on #ResponseBody from the Documentation

Related

spring security & axios - email: "NONE_PROVIDED"

Logging in via postman works fine ONLY when using application/x-www-form-urlencoded
Trying to do the same request with raw-json doesn't work.
Anyway I'm trying to implement the login to my react app. When i have the request set as:
const response = await Axios.post(`${window.ipAddress.ip}/login`,
JSON.stringify({ email: email.toLowerCase(), password: password }),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);
From this in springboot the UserService class gets called which shows:
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = findUserByEmail(email);
if ( user != null){
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
user.getRoles().forEach(role -> { authorities.add(new SimpleGrantedAuthority(role.getName()));});
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), authorities);
}
else{ throw new EntityNotFoundException("Entity not found"); }
}
It then shows email as "NONE_PROVIDED" and ultimately failing.
The second issue is I don't actually have a /login route in controller code when searching through all files so I'm unsure at which point it actually calls this method through springboot.
The only changes I made from the default spring-security implementation is the use of my own class where I use "email" in place of "userName".
Any suggestions are welcome.
Edit:
the working login function via postman
Springboot was expecting encoded form which is different from my other requests , this answer shows how to properly outline x-www-for-urlencoded
axios post request to send form data
having the request as:
var bodyFormData = new FormData();
bodyFormData.append('email', email.toLowerCase());
bodyFormData.append('password', password);
const response = await Axios({
method: "post",
url: `${window.ipAddress.ip}/login`,
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" },
})

Request failing error message when passing data from react application to web service

I have a javascript object and when I stringify It, I get the data below which
is called dataToJson
0: {invoiceId: 45233265}
1: {invoiceId: 89238545}
2: {invoiceId: 65235465}
Here is my endpoint written with spring.io which should accept the json data
above. I decided not to include all the code in the method because it works.
All I need is how to pass the data.
#ApiOperation(
value = "Returns a pageable list of data.",
notes = "Must be authenticated.")
#EmptyNotFound
#GetMapping({
"customers/{customerId}/getProductsForInvoices/{invoiceIds}"
})
public ArrayList<Page<CustomerInvoiceProduct>> getProductsForInvoices(
#PathVariable(required = false) Long customerId,
#RequestBody List<CustomerInvoice> invoiceIds,
Pageable pageInfo) {
......
......
return result;
}
Here is how I am using Axios to make the web service call and pass in the data.
AXIOS_AUTHED.get(`${API}/customers/${getCustomerId}/getProductsForInvoices/invoiceIds`, {
params:dataToJson
})
.then(function (response) {
console.log(response);
console.log(dataToJson);
})
.catch(function (error) {
console.log(error);
console.log(dataToJson);
});
All I get is "request failed with status code 400"
When I pass data like this from postman, it works very well.
[
{
"invoiceId":"45233265"
},
{
"invoiceId":"89238545"
},
{
"invoiceId":"65235465"
}
]

Axios Post in react js is giving error No 'Access-Control-Allow-Origin' header is present on the requested resource

I am trying to do create Login page using react in my web application with spring boot in backend. I am using spring security JDBC Authentication for login. I am trying to convert my JSP pages to React. Login is working fine with JSP and spring boot. Now i am trying to create same page with react. but when i post using axios post i am getiing error
Access to XMLHttpRequest at 'http://localhost:8080/onlineshopping/login' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
this is axios Post
export const Login = (username, password) => async dispatch => {
console.log(password)
let params = {
username: username,
password: password
}
const res = await axios.post("http://localhost:8080/onlineshopping/login", {params});
dispatch({
type: Login,
payload: res.data
});
};
SecurityConfig.java
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.usersByUsernameQuery("select email, password, enabled from user_detail where email = ?")
.authoritiesByUsernameQuery("select email, role from user_detail where email = ?")
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
Pagecontroller.java
#RestController
#CrossOrigin
public class PageController {
#RequestMapping("/login")
public Map<String, Object> login(
#RequestParam(name = "error", required = false) String error,
#RequestParam(name = "logout", required = false) String logout) {
Map<String, Object> map = new HashMap<String, Object>();
System.out.println("Login");
map.put("title", "Login");
if (error != null) {
map.put("message", "Username and Password is invalid!");
}
if (logout != null) {
map.put("logout", "You have logged out successfully!");
}
return map;
}
}
Please tell me why i am getting this error and how to solve it.
You have to add proxy address to your package.json file, e.g.:
},
"proxy": "http://localhost:8080",
"devDependencies": {
Next, you just add all the which is after the localhost, i.e.
axios.get("/onlineshopping/login")
After adding CORS filter configuration in spring boot and content type to application/x-www-form-urlencoded in axios request my problem solved.
export const addProjectTask = (username,password, history) => async dispatch => {
axios.post('http://localhost:8080/onlineshopping/login',
Qs.stringify({
username: username,
password: password
}), {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
.then(function (response) {
console.log(response);
history.push("/");
})
.catch(function (error) {
console.log(error);
});
};
You have to create a proxy for API calls.
Here, proxy uses url pattern to match to the api calls and redirecting them to the corresponding server.
Try with the following:
Install http-proxy-middleware
npm install http-proxy-middleware --save
create src/setupProxy.js
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(proxy('/api', { target: 'http://localhost:8080/' }));
};
Then run your local Dev server

Angular POST to Spring Security JWT login always returns Unauthorized

I've set-up a stateless Spring Security application that uses JWT tokens for authentication. I've launched the application and tried to login over Postman with credentials I inserted into the database using a POST method (I've tried both form data and x-www-form-urlencoded) and it works successfully, it returns the JWT token and the expiration time. However, when I try to post to the same URL over Angular I always get Unauthorized; Bad credentials no matter if I use correct username-password combo.
I've tried POSTing 3 ways:
1
#Injectable()
export class AuthService {
constructor(private http: HttpClient) {
}
login(username: string, password: string): Observable<any> {
return this.http.post(environment.api + '/auth/login', {
'username': username,
'password': password
});
}
}
2
login(username: string, password: string): Observable<any> {
let body = 'username=' + username + '&password=' + password;
let headers = new HttpHeaders();
headers.set('Content-Type', 'x-www-form-urlencoded');
return this.http.post(environment.api + '/auth/login', body, {
headers: headers
});
}
3
login(username: string, password: string): Observable<any> {
let body = new URLSearchParams();
body.set('username', username);
body.set('password', password);
return this.http.post(environment.api + '/auth/login', body);
}
But every single method keeps returning 401: Unauthorized, as if my username and password are always wrong (and I keep trying with correct ones that work on Postman). What am I doing wrong?
Here I share a piece of my Angulare login service that sends a login request to a Spring Login Controller running under localhost 8181. I hope this will help.
import { Injectable } from '#angular/core';
import {Http, Headers} from '#angular/http';
import {Observable} from 'rxjs/Observable';
#Injectable()
export class LoginService {
constructor(private http: Http) { }
sendCredential(username: string, password: string) {
let url = "http://localhost:8181/token";
let encodedCredentials = btoa(username+":"+password);
let basicHeader = "Basic "+encodedCredentials;
let headers = new Headers ({
'Content-Type' : 'application/x-www-form-urlencoded',
'Authorization' : basicHeader
});
return this.http.get(url, {headers: headers});
}
Found the problem, it was in the HttpClient itself not sending post data correctly for unknown reasons. Tried it with the Http service and it works as it should.

Forms validation in Nancy not working with AJAX login requests

I'm trying to implement an extremely simple spike using Nancy as an alternative to ASP.NET MVC.
It should take a username (no password) and provide meaningful error messages on the same login page without requiring a refresh. If login was successful, the response includes the URL to navigate to.
The POCO for the response looks like this:
public class LoginResponseModel
{
public bool IsSuccess { get; set; }
public string RedirectUrl { get; set; }
public string ErrorMessage { get; set; }
}
The JS handler for the login request:
$.ajax({
url: '/login',
type: "POST",
data: { UserName: username }
}).done(function (response) {
if (response.IsSuccess) {
showSuccess();
document.location.href = response.RedirectUrl;
return;
}
showError(response.ErrorMessage);
}).fail(function (msg) {
showError("Unable to process login request: " + msg.statusText);
});
The problem I'm having is with Nancy's Forms-based authentication. I've walked through half a dozen different tutorials which all more or less do the same thing, as well as gone over the Nancy authentication demos. The one thing they all have in common is that they rely on the LoginAndRedirect extension method. I don't want to return a redirect. I want to return a result of the login attempt and let the client handle the navigation.
The IUserMapper implementation I'm using:
public class UserMapper : IUserMapper
{
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
{
// Don't care who at this point, just want ANY user...
return AuthenticatedUser {UserName = "admin"};
}
}
The relevant part of my LoginModule action:
var result = _userMapper.ValidateUser(input.AccessCode);
if (result.Guid != null) this.Login(UserMapper.GUID_ADMIN, expiry);
return Response.AsJson(result.Response);
but for subsequent requests Context.CurrentUser is always null.
If I add the following method to the Nancy.Demo.Authentication.Forms sample it reproduces the behaviour I'm seeing in my own project, leading me to believe LoginWithoutRedirect doesn't work how I expected.
Get["/login/{name}"] = x =>
{
Guid? userGuid = UserDatabase.ValidateUser(x.Name, "password");
this.LoginWithoutRedirect(userGuid.Value, DateTime.Now.AddYears(2));
return "Logged in as " + x.Name + " now <a href='~/secure'>see if it worked</a>";
};
The problem turns out to be that Context.CurrentUser with FormsAuthentication is dependent upon a cookie which isn't set if you don't return the NancyModule.Login() response.
var result = _userMapper.ValidateUser(input.AccessCode);
if (result.IsSuccess) {
this.LoginWithoutRedirect(result.Guid);
}
return Response.AsJson(result);
In this example, the LoginWithoutRedirect call returns a Response object with the cookie set. To handle this in an Ajax scenario I've had to add a AuthToken property to the LoginAjaxResponse class, then pass the cookie like so:
var result = _userMapper.ValidateUser(input.AccessCode);
var response = Response.AsJson(result);
if (result.IsSuccess) {
var authResult = this.LoginWithoutRedirect(result.Guid);
result.AuthToken = authResult.Cookies[0].Value;
}
return Response.AsJson(result);
On the client, the Ajax response handler changes to (assuming use of jQuery cookie plugin:
$.ajax({
url: '/login',
type: "POST",
data: { UserName: username }
}).done(function (response) {
if (response.IsSuccess) {
showSuccess();
$.cookie("_ncfa", response.AuthToken); // <-- the magic happens here
document.location.href = response.RedirectUrl;
return;
}
showError(response.ErrorMessage);
}).fail(function (msg) {
showError("Unable to process login request: " + msg.statusText);
});
The AuthToken is the GUID which has been encrypted and base64-encoded. Subsequent requests with this.RequiresAuthentication() enabled will first check for this auth token cookie.
If no "_ncfa" cookie is present,the UserMapper's GetUserFromIdentifier() is never called.
If the value in Context.Request.Cookies["_ncfa"] does not result in a valid GUID when base64-decoded and decrypted, GetUserFromIdentifier() is never called.
If GetUserFromIdentifier() isn't called, Context.CurrentUser is never set.
If you want the source for a working example it's on GitHub.
LoginAndRedirect is only one option, there are equivalent methods for not redirecting (LoginWithoutRedirect), or one that picks up on whether it's an AJAX request and handles it appropriately (Login). The same applies to logging out.
This is all covered, in detail, in the documentation.

Resources