How to login user to spring-security app using Vue.js? - javascript

Hi it's my first post on stack overflow. I want to separate back-end from front-end and create REST API using my Spring Boot app. I use spring-security to login. It use something called JSESSION_ID but how to login and authorize users using Vue.js? I want to make form for login to my service and authorize request with JSESSION_ID.
It's my first app in Vue.js. I try to use code from tutorials and docs but it didn't solve my problem. I also have issues with CORS.
export default {
name: 'Login',
data(){
return{
username: '',
password: '',
error: false
}
},
updated(){
if (localStorage.token){
this.$router.replace(this.$route.query.redirect || '/')
}
},
methods:{
login(){
this.$http.post('http://localhost:8080/login', { username: this.username, password: this.password })
.then(request => this.loginSuccessful(request))
.catch(() => this.loginFailed())
},
loginSuccessful (req) {
if (!req.data.token) {
this.loginFailed();
return
}
this.error = false;
localStorage.token = req.data.token;
this.$router.replace(this.$route.query.redirect || '/')
},
loginFailed () {
this.error = 'Login failed!';
delete localStorage.token
}
}
}
I expect to login and authorize users from Vue.js using REST Spring-Boot API.

The problem is that you try to pass the object { username: this.username, password: this.password } as the data to the request, but you do not specify the Content-Type, which probably defaults to 'text/html' or 'application/json'. You could try to first convert that into form data and then pass it to the request, here is an example with AXIOS:
login() {
let formData = new FormData();
formData.set("username", this.username);
formData.set("password", this.password);
AXIOS.post('/login', formData, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.then((result) => {
this.loginSuccessful(result);
})
.catch((error) => {
this.loginFailed();
})
}
Perhaps it would also work without specifying the header, like AXIOS.post('/login', formData, null), haven't tried it.

Related

When i trying to wirte data in firebase db take an exception

I have got an a react native app, i need to save data in db with user's token. How can i do it?
It's my auth firebase:
Also i need an a real time db to save here data and user's token:
I have a registration of user, and i know that i need here to make an a api into realtime db mthod PUT for url: https://[PROJECT ID]-default-rtdb.firebaseio.com/, but how can i do it i didn't know, pls help:
const hanldeRegister = () => {
if (password !== confirmPassword){
alert("The passwords are different!")
}
else{
setIsLoading(true)
axios({
method: 'POST',
url: 'https://identitytoolkit.googleapis.com/v1/accounts:signUp',
params: {
key: 'A',
},
data: {
email,
password,
},
}).then((res) => {
axios({
method: 'POST',
url: 'https://identitytoolkit.googleapis.com/v1/accounts:update',
params: {
key: 'A',
},
data: {
idToken: res.data.idToken,
displayName: name + ' ' + surname
}
}).then((r) => {
setUser({...r.data, idToken: res.data.idToken})
}).catch(e => {
console.log(e, 'updaate profile error');
alert(e.message);
})
.finally(() => {
setIsLoading(false);
})
console.log(res.data)
})
.catch((error) => console.log(error.response.request._response))
}
}
Rather than attempt to explain the process in great depth, because that would be reiterating the already existing docs.
Here is a link to the getting started docs regarding firestorage.
https://firebase.google.com/docs/storage/web/start
You should also checkout the starting docs, in regards to setting up firebase with web.
https://firebase.google.com/docs/web/setup
Thi will guide you through the process of setting up and intergrading firebase with your JavaScript application.

Electron - data from external API being passed to Vue renderer disappears

I'm building an app using Electron, the Quasar UI framework, and Vue 3. The app talks to a Laravel backend using a REST API, but I've had trouble with the login process, particularly passing the data from the main process to the renderer process as it involves promises.
I'm using the #electron/remote to pass the data from the renderer process to the main process. I've set this up in the src/electron-main.js file as per this tutorial.
Here is the code that actually sends the API login request:
src-electron/electron-preload.js
import {contextBridge} from 'electron';
contextBridge.exposeInMainWorld('electronApi', {
getJwtFromServer: async (email, password, server) => {
fetch(
`https://login.${server}/api/v1.1/auth/login`, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'x-api-key': '<api key goes here>',
'Cookie': 'XDEBUG_SESSION=PHPSTORM',
},
body: new URLSearchParams({
'email': email,
'password': password
})
}).then(res => {
res.json()
.then(data => {
return data.token;
}).catch(error => {
return error.msg;
})
}).catch(error => {
return error.msg;
})
},
}
});
In the frontend, I then have an Electron API (in TypeScript) which intercepts the data from the main process and forwards it to the renderer:
src/api/electron-api.ts
export interface ElectronApi {
getJwtFromServer: (
email: string,
password: string,
server: string
) => Promise<object>;
}
export const electronApi: ElectronApi = (window as {electronApi: ElectronApi})
.electronApi;
Then in the Vue app I invoke the Electron API, which calls the function in the main process and sends a request to the backend. The correct data is returned to the backend, yet it seems to get lost before it reaches the Vue app.
LoginPage.vue
import {electronApi} from '../api/electron-api';
export default {
data() {
return {
server: '',
email: '',
password: '',
token: ''
}
},
methods: {
loginUser() {
electronApi.getJwtFromServer(this.email, this.password, this.server)
.then((res) => {
console.log("Fetched token: ", res);
this.token = res;
})
},
}
};
The console.log() in the LoginPage.vue component is always undefined. Where is the data getting lost along the way?

Using tokens to authorize in Sanctum

I want to use React with Sanctum. In Sanctum, I generated the token and return it after login, and it works correctly. However, after login, I can see my token in the console, but if I want to open the route for logged-in users, I must send this token in the header. What is the best method to do that?
public function login(Request $request)
{
$attr = $request->validate([
'email' => 'required|string|email|',
'password' => 'required|string|min:6'
]);
if (!Auth::attempt($attr)) {
return $this->error('Credentials not match', 401);
}
return response()->json([
'access_token' => auth()->user()->createToken('auth_token')->plainTextToken,
'token_type' => 'Bearer',
]);
}
And login into React.
function Login () {
const emailRef = useRef(),
passwordRef = useRef();
const handleSubmit = (event) => {
event.preventDefault();
axios.post('http://localhost:8000/api/auth/login', { email: emailRef.current.value, password: passwordRef.current.value })
.then(res => {
console.log(res);
}).catch((error) => {
console.log(error)
});
}
return(
// Here is my form
);
}
#Edit
I don't sure I good understand but it doesn't work. If I try to get address witch need to autorize I have a status 401.
I make instance
instance.php
import axios from 'axios'
let instance = axios.create({
baseURL: 'http://localhost:8000',
headers: {
common: {
'X-Requested-With': 'XMLHttpRequest',
}
},
withCredentials: true,
});
export default instance;
And I login user. In React it look like this
instance.post('/api/auth/login', {
email: emailRef.current.value,
password: passwordRef.current.value
}).then(res => {
console.log(res);
})
Generally it works. I want to add someting which need to authorize.
instance.get('/api/me')
.then(res => {
console.log(res.data.data.token);
}).catch((error) => {
console.log(error)
});
And in Api.php it look like this
Route::post('/auth/register', [AuthController::class, 'register']);
Route::post('/auth/login', [AuthController::class, 'login']);
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::get('/me', function() {
echo "Hello World";
})->name('me');
Route::post('/auth/logout', [AuthController::class, 'logout']);
});
You should be able to not need to store anything in any special place by just using Axios config like this:
axios.create({
headers: {
common: {
'X-Requested-With': 'XMLHttpRequest',
},
},
withCredentials: true,
});
The withCredentials: true will store the CSRF token and any credential once you login, so you would not have to worry anymore about sending any credentials or anything like so.
This is another example.
You could also take advantage of Axios and also delete any data you have store when a request returns 401 (Unauthorized) or 419 (Session Expired).
authClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response &&
[401, 419].includes(error.response.status) &&
store.getters[`user/${IS_GUEST_GETTER}`]
) {
store.dispatch(`user/${LOGOUT_ACTION}`);
}
return Promise.reject(error);
}
);
In this example, I am using a store like vuex and I am asking first if the current user is a guest or not, and then deleting everything from the session with a simple logout (on Vue and Laravel).
You can do this with Interceptors.
How to Fix CSRF token issue using JavaScript (without jQuery)
Error I was facing.
419 PAGE EXPIRED
message : "CSRF token mismatch.", exception: "Symfony\Component\HttpKernel\Exception\HttpException"
My Route is protected with auth:sanctum, above snippet also worked with auth middleware.
Route::post('/media/upload', MediaController::class)
->middleware('auth:sanctum')
->name('media.upload');
1st add <meta name="csrf-token" content="{{ csrf_token() }}"> in app.blade.php
2nd: Get the csrf-token value using document.querySelector('meta[name="csrf-token"]').getAttribute('content')
Snippet headers settings
headers: {
"Accept": "application/json",
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
},
"Accept": "application/json" for 419 PAGE EXPIRED fixing.
'X-CSRF-TOKEN': document.querySelector('me... for CSRF token mismatch.
It worked either you are using axios, Ajax, XHR, uppy.io XHRUpload, or SPA
$.ajax({
type:'POST',
url:'/ajax',
headers: {
"Accept": "application/json",
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
},
});

Where to put API session auth token in SDK request methods?

I am using the ConnectyCube React Native SDK and have obtained an app auth token using their API. This token is required when making further requests - for example when logging in as a user. Their documentation says:
Upgrade session token (user login)
If you have an application session token, you can upgrade it to a user session by calling login method:
var userCredentials = {login: 'cubeuser', password: 'awesomepwd'};
ConnectyCube.login(userCredentials, function(error, user) {
});
The problem is it that when I use this method, I get an error in response saying 'Token is required'.
If I were interfacing with a REST API, I would put the token in the header of the request, but obviously in this instance I can't. So the question is, where do I put the token? I have it, the documentation just doesn't tell you how to use it! Any help appreciated.
Ok I came up with a fix. First of all I just tried passing the auth token in to the userCredntials object in the same way as in the documentation for social auth, that is absent from the description in my above code snippet taken from their docs.
Then I Promisified the API calls from within useEffect inside an async function to make sure everything was happening in the right order, and it works:
export default function App() {
const createAppSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
!error
? resolve(session.token)
: reject(error, '=====1=====');
});
})
}
const loginUser = (credentials) => {
return new Promise((resolve, reject) => {
ConnectyCube.login(credentials, ((error, user) => {
!error
? resolve(user)
: reject(error, '=====2=====');
}));
})
}
useEffect(() => {
const ccFunc = async () => {
ConnectyCube.init(...config)
const appSessionToken = await createAppSession();
const userCredentials = { login: 'xxxxx', password: 'xxxxxxx', keys: { token: appSessionToken } };
const user = await loginUser(userCredentials);
console.log(user);
}
ccFunc()
}, []);
Hope it works....
please implement it by yourself...just take an understanding from code below.
code says: send the username and password to api...if all ok then authenticate else throw error ...if all ok..then store the returned token is asyncStorage...you can create the storage by any name you like...and use the token eveywhere in your app.
SignInUser = async () => {
this.setState({
username: this.state.username,
password:this.state.password,
})
if(this.state.username && this.state.password !== null){
try{
this.setState({
loading:true
})
const response = await fetch('YOUR API', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: this.state.username,
password: this.state.password
})
});
var promiseResponse = await response.json()
console.log(promiseResponse.token);
try {
await AsyncStorage.setItem('STORE_YOUR_LOGIN_TOKEN_HERE', JSON.stringify(promiseResponse.token));
console.log('Token Stored In Async Storage');
let tokenFromAsync = await AsyncStorage.getItem('STORE_YOUR_LOGIN_TOKEN_HERE');
console.log('Getting Token From Async...')
tokenFromAsync = JSON.parse(tokenFromAsync)
if(tokenFromAsync !== null){
console.log(tokenFromAsync);
this.setState({
loading:false
})
this.props.navigation.navigate('Tabnav');
}
} catch (error) {
// saving error
console.log(`ERROR OCCURED ${error}`)
}
//this.props.navigation.navigate('Tabnav')
} catch(error){
console.log(`COULDN'T SIGN IN ${error}`)
}
} else {
this.setState({
msg:'Invalid Credentials',
label:'red'
});
}
}
This is how i got the login to work in their sample react native app 1. i created a credentials object like this in my custom login function in src>components>AuthScreen>AuthForm.js
var credentials = {id:'',login: this.state.login,password: this.state.password}
2.I used their _signIn(credentials) function and set the 'id' attribute of my credentials object after their UserService.signin(credentials) resolved with a user object. (the resolved user object contained the logged-in user's id i.e user.id). Then it worked. This is how the code looked for the signin after the little tweak.
loginUser() { //my custom signin function
var credentials = {id:'',login: this.state.login,password: this.state.password} //my credentials object
this._signIn(credentials)
}
_signIn(userCredentials) { //their signin function
this.props.userIsLogging(true);
UserService.signin(userCredentials)
.then((user) => {
userCredentials.id = user.id //setting id of my credentials object after promise resolved
ChatService.connect(userCredentials) //using my credentials object with id value set
.then((contacts) => {
console.warn(contacts)
this.props.userLogin(user);
this.props.userIsLogging(false);
Actions.videochat(); //login worked
})
.catch(e => {
this.props.userIsLogging(false);
alert(`Error.\n\n${JSON.stringify(e)}`);
})
})
.catch(e => {
this.props.userIsLogging(false);
alert(`Error.\n\n${JSON.stringify(e)}`);
})
}

Switching from MockBackend to Actual API in Angular 2 App

I am working on login functionality for my Angular 2 app. I've got it working with a MockMackend and fakeBackendProvider. Now I'm in the process of connecting to our actual API. I am running into an issue with that, though.
First off, let me show what I have that IS working by using the MockBackend and fakeBackendProvider.
This is my authentication service function:
login(username: string, password: string) {
return this.http.post('/api/authenticate', JSON.stringify({ username: username, password: password}))
.map((response: Response) => {
// login successful if there's a jwt token in the response
const user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
Again, then, in my login component, I am calling that function like this:
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.router.navigate(['/']);
console.log('User logged in as: ' + this.model.username);
},
error => {
this.alertService.error(error);
this.loading = false;
});
this.authenticationService.username = this.model.username;
}
Again, all of the above IS working.
So, I assume all I should need to do is replace '/api/authenticate' in the login function, with our actual api + api string. So this is what I've been trying:
login(username: string, password: string) {
return this.http.post('https://api.somesite.com&apikey=843c-4932-ckd33', JSON.stringify({ username: username, password: password}))
.map((response: Response) => {
// login successful if there's a jwt token in the response
const user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
This isn't working. In the console I get a "ERR_NAME_NOT_RESOLVED" error. Any ideas here?

Categories

Resources