I'm able to register a new user and save in my database, but unable to login, I get a 'Forbidden error : 403' whenever I try to login,
Relevant Code block below:
Sign-in Page
authController.login(email, password).then((status){
if(status.isSuccess){
print("We're In!");
Get.toNamed(RouteHelper.getInitial());
}else{
print("Failed To Login "+status.toString());
showCustomSnackBar(status.message);
}
authController
Future<ResponseModel> login(String email,String password) async{
_isLoading = true;
update();
Response response = await authRepo.login(email, password);
late ResponseModel responseModel;
if (response.statusCode == 200){
print("Backend token");
authRepo.saveUserToken(response.body["token"]);
print(response.body["token"].toString());
responseModel = ResponseModel(true, response.body["token"]);
}else{
responseModel = ResponseModel(false, response.statusText!);
print("Unsuccessful retrieval of token from Server: " + response.statusCode.toString());
}
I tried using postman to send a Post request, I thought I wasn't receiving the token, but I'm able to retrieve a Token successfully.
By the way, I'm working on a localhost for now with Laravel backend + VS Code + Flutter, what could be the problem?
This should work i think you forgot to define username to the variable
'username' <--[api] : username <--[variable],
authController
Future<ResponseModel> login(String email,String password) async{
_isLoading = true;
update();
Response response = await authRepo.login, body: {
'username': username,
'password': password,
});
late ResponseModel responseModel;
if (response.statusCode == 200){
print("Backend token");
authRepo.saveUserToken(response.body["token"]);
print(response.body["token"].toString());
responseModel = ResponseModel(true, response.body["token"]);
}else{
responseModel = ResponseModel(false, response.statusText!);
print("Unsuccessful retrieval of token from Server: " + response.statusCode.toString());
}
Related
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" },
})
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
I have a Web API service hosted in Microsoft Azure. I need a certain POST method to be only accessible with one unique username and password.
I understand the [Authorize] method does a token based authentication but its not tied to a single username and password. In my app, the web api also does the login authentication, so anyone who registers can access this post method if im not mistaken. (Please correct me if im wrong)
I am new to this could you guide me the right way please.
This is my WebAPI Post method i want to secure access to with specific unique username&pass:
[AllowAnonymous]
[HttpPost, Route("send")]
public async Task<NotificationOutcome> Post([FromBody]string message)
{
string hubName = "myHub";
string hubNameDefaultShared = "myHubNameDefaultShared";
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString(hubNameDefaultShared, hubName, enableTestSend: true);
string installationId = string.Empty;
var templateParams = new Dictionary<string, string>
{
["messageParam"] = message
};
NotificationOutcome result = null;
if (string.IsNullOrWhiteSpace(installationId))
{
result = await hub.SendTemplateNotificationAsync(templateParams).ConfigureAwait(false);
}
else
{
result = await hub.SendTemplateNotificationAsync(templateParams, "$InstallationId:{" + installationId + "}").ConfigureAwait(false);
}
return result;
}
And this is how I currently access the POST Method:
var client = new RestClient("myWebApiRouteName");
var request = new RestRequest(Method.POST);
request.AddHeader("Postman-Token", "46c23eba-8ca6-4ede-b4fe-161473dc063a");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("undefined", messageBody, ParameterType.RequestBody);
try
{
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I'm following this tutorial, currently I can log in and out with a user but when a user logs in the JWT token isn't send with the header request (I think) so I get a 401 after the router.navigate. When I reload the page I can use the token and everything works.
In my login.component.ts I have this login function:
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(result => {
if (result === true) {
// login successful
this.router.navigate(['home']);
} else {
// login failed
this.error = 'Username or password is incorrect';
this.loading = false;
}
}, error => {
this.loading = false;
this.error = error;
});
}
This calls the login function in the authentication.service.ts:
login(username: string, password: string): Observable<boolean> {
return this.http.post(this.authUrl, JSON.stringify({username: username, password: password}), {headers: this.headers})
.map((response: Response) => {
// login successful if there's a jwt token in the response
const token = response.json() && response.json().token;
if (token) {
// store username and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));
// return true to indicate successful login
alert('Success');
return true;
} else {
// return false to indicate failed login
alert('Fail');
return false;
}
}).catch((error: any) => Observable.throw(error.json().error || 'Server error'));
}
If the login is successful the user is routed to /home:
this.router.navigate(['home']);
In the home.component.ts I have a getAll function that returns all movies in the database:
getAll() {
this._dataService
.getAll<Movie[]>()
.subscribe((data: any[]) => this.movies = data,
error => () => {
'something went wrong';
},
() => {
console.log(this.movies);
});
}
This function is called on the ngOnInit:
ngOnInit(): void {
this.getAll();
}
In my app.service.ts I have the get function:
public getAll<T>(): Observable<T[]> {
if (this.authenticationService.getToken()) {
console.log(this.authenticationService.getToken());
console.log(this.headers);
return this.http.get<T[]>('/api/movies/all', {headers: this.headers});
}
}
But when I log in I get this error after being routed to the home page:
GET http://localhost:4200/api/movies/all 401 (Unauthorized)
The problem (I think) is that when I get routed to the home page the header is missing the token. But as you can see from the console log the token is available in app.service.ts.
When I reload the page I do have the token set in the header and everything works:
Any ideas on how to expose the token to the header after the redirect?
//EDIT
For some reason I do get the JWT token when I set the header directly in the function:
return this.http.get<T[]>('/api/movies/all', {headers: new HttpHeaders().set('Authorization', 'Bearer ' + this.authenticationService.getToken())});
Instead of calling it like this:
headers = new HttpHeaders().set('Authorization', 'Bearer ' + this.authenticationService.getToken());
return this.http.get('/api/movies/' + id, {headers: this.headers});
I have an ASP.NET Core project that has a Web API for mobile device (Xamarin).
I want to secure the api with ASP.NET Core identity, but the problem is when I authenticate a device and authenticated successfully, in another request it not still authenticated:
[HttpPost]
public async Task<IActionResult> Post([FromBody] LogIn l)
{
var user = await userManager.FindByEmailAsync(l.username);
if(user == null)
{
user = await userManager.FindByNameAsync(l.username);
}
if(user != null)
{
await signInManager.SignOutAsync();
Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(user, l.password, false, false);
if (result.Succeeded)
{
await signInManager.RememberTwoFactorClientAsync(user);
return Ok("Success");
}
}
return Ok(HttpStatusCode.BadRequest);
}
The code that needs to authorize to return data :
[HttpGet("{id}")]
[Authorize]
public async Task<IActionResult> Get(int id)
{
var b = _context.Books.FirstOrDefault(o => o.BookId == id);
return Ok(b);
}
I read about token and jwt but I don't know how to use them. Any Idea how to secure the API and make the device authenticated once they log in?
I know it's late, but I think the idea is to login the user, and return a token that's then saved to the client's(Xamarin Android/iOS for your case) local storage/Sharedpreferences. The saved token can then be used for subsequent Web API calls for authentication without the need to login. It can then be cleared when a user logs out. For JWT, you can restructure your login function as follows:
var token = await GetJwtSecurityToken(user);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
The GetJwtSecurityToken() can look like this depending on your needs:
private async Task<JwtSecurityToken> GetJwtSecurityToken(ApplicationUser user)
{
var userClaims = await _userManager.GetClaimsAsync(user);
return new JwtSecurityToken(
//issuer: "http://localhost:****/",
//audience: "http://localhost:****/",
audience: "http://localhost:****/",
claims: GetTokenClaims(user).Union(userClaims),//Combine user & claims
//expires: DateTime.UtcNow.AddMinutes(10),
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes("x%u<-Q.#w^:qF]2Hz4")), SecurityAlgorithms.HmacSha256)
);
}
The GetTokenClaims() function can look like:
private static IEnumerable<Claim> GetTokenClaims(ApplicationUser user)
{
return new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("UserName", user.UserName),
new Claim("Email", user.Email),
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim("FirstName", user.FirstName)
//Other user info
};
}
You can then save this token in local storage/Sharedpreferences, and use it to authenticate your API calls. You can research on: How to decode JWT token in Xamarin, OpenId..
Let me know how it goes.