I want to implement a user authentication based on ReactJS component. I'm new to ReactJS and it's a group software project, so we don't use webhooks but components. The Authentication itself is working but not the rendering afterwards of the content.
In the app.js file I used conditional rendering, to either show the content or the login page:
if (this.getToken('token') === null || this.getToken('token') === undefined) {
shownComponent = <LoginComponent token={this.state.token} setToken={this.setToken} />;
} else {
shownComponent = <MainComponent />;
}
In the LoginComponent I implemented the following logic:
registerUser = () => {
const data = {
userName: this.state.userName,
userPassword: this.state.userPassword
}
return fetch('/users/createUser', {
method: 'post',
mode: 'cors',
headers:{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json'
},
body: JSON.stringify(data),
})
.then((data) => {
if(data.status === 200){
console.log('User has been stored to database');
return true
}
})
.catch((error) => console.log( error.response.request) );
}
loginUser = () => {
return fetch('/login',{ headers:{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json'
} })
.then((response) =>{
return response.json();
})
.then((data) =>{
return data;
});
}
login = async () => {
this.setState({loggedin: true})
const registered = await this.registerUser()
const userToken = await this.loginUser();
this.props.setToken(userToken)
}
after calling the login function from the login form (not copy pasted in here) it would only re-render the login page but not redirect back to the app.js and render now the main content.
Related
I'm making an app with React as the front end and am handling authentication with knox. Everything is working fine but I require the ability for users to login to premade demo accounts without inputting any credentials. I can't figure out how to do this with Knox on the backend and I can't have the login info stored in my javascript. Any ideas how to accomplish this?
Knox:
class LoginAPI(KnoxLoginView):
authentication_classes = [BasicLikeAuthentication]
def get_post_response_data(self, request, token, instance):
user = request.user
data = {
'expiry': self.format_expiry_datetime(instance.expiry),
'token': token,
'user': user.username,
'role': user.roles.assigned_role
}
return data
Front end for regular login:
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
const credentials = btoa(`${data.get('username')}:${data.get('password')}`);
const requestOptions = {
method: "POST",
credentials: 'include',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
"Authorization": `Basic ${credentials}`
},
body: JSON.stringify({})
}
fetch('http://127.0.0.1:8000/api/login/', requestOptions)
.then(response => {
if (response.status === 401) {
setFailedLogin(true)
}
return response.json()
})
.then(data => {
localStorage.setItem('token', data['token'])
})
.then(fetchCurrentUser)
.then(() => {
localStorage.getItem('role') == "Admin"
? navigate("/manage")
: navigate("/maindash")
})
.catch(error => console.log(error))
}
I want to redirect the user after successful login to the home page, But nothing works.
This is my Login.js component
Also, I could not get parameter URL in class-based components and I was forced to use functional component and I use let params=useParams(); to get URL parameters
function Login(props) {
const sendSms = async (e=null) => {
if (typeof(securityCode) !=='undefined' && securityCode.toString().length === 6) {
const response = await fetch('http://localhost:8000/api/login/' ,{
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
mobile,
securityCode
})
});
const data = await response.json();
let result=data.result;
let message=data.message;
if (result === 'success') {
clearInterval(sms_interval);
setToken(data.data);
return navigate("/", { replace: true }); //important
return false;
} else {
setAlertClass('alert-danger');
setAlertMessage(message);
}
return false;
}
fetch('http://localhost:8000/api/send_sms/' ,{
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
mobile
})
})
.then(response => response.json())
.then(data => {
let result=data.result;
let message=data.message;
if (result === 'success') {
let sms_timer = 120;
setSmsInteral(setInterval(function () {
if (sms_timer > 0) {
}, 1000)
);
} else {
}
});
return false;
}
}
The useHistory hook is no longer present with React Router 6.
Try to use the useNavigate hook and convert the function to use async / await:
import { useNavigate } from "react-router-dom";
function Login(props) {
const navigate = useNavigate();
const verify = async (e = null) => {
try {
const response = await fetch("http://localhost:8000/api/login/", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
mobile,
securityCode,
}),
});
const data = await response.json();
let result = data.result;
let message = data.message;
if (result === "success") {
clearInterval(sms_interval);
setToken(data.data);
navigate("/");
} else {
sms_alert_element.classList.add("alert-danger");
sms_alert_element.innerText = message;
}
return false;
} catch (err) {
console.log(err);
}
};
}
How to mock the fetch statement using jest
export default function Login() {
function LoginUser() {
const requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({ username: username, password: password }),
};
fetch('http://localhost:8080/post', requestOptions)
.then((response) => {
if (response.status === 200) {
console.log('succesfull');
} else {
throw new Error('Invalid credentials');
}
})
.catch((err) => {
console.log(err);
});
}
<Button
block
size='lg'
type='submit'
onClick={LoginUser}
disabled={!validateForm()}
>
Login
</Button>;
}
The above code should be unit tested using mock jest on click the loginuser the function is fetch the post request.
I'm fairly new to React and I've been trying to create a SignUp page, however, I'm stuck in this error. Can someone give me any indication on what I should do in order to solve this error?
Signup Method:
// = Action =
// Sign up
export const signup = user => {
return fetch(
`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
}
Rewrite Signup method (ps: I only changed the .catch handler)
`
// Sign up
export const signup = user => {
return fetch(
`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err =>
console.log(err));
return err;
}
`
You need to wrap up your fetch logic inside a Promise to return a value to the caller.
export const signup = user => {
return new Promise((resolve, reject) => {
fetch(`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => response.json())
.then(jsonData => resolve(jsonData))
.catch(err => resolve({error: `something went wrong err : ${err}`}));
})
}
signup(user).then(data => {
if (data.error) {
// handle error case
} else {
// handle success case
}
})
Now your signup method will return a value. Your data variable won't be undefined anymore.
I hope it helps, feel free to add comments or ask me more details
I'm trying to refresh some data when users re-vistis the screen. The way im using other places and it works. but can't figure out why this won't fly on this screen?
componentDidMount = () => {
this.props.navigation.addListener('didFocus', this.handleDidFocus)
}
async handleDidFocus() {
...
}
This is how I load data the first time and want to load it again when users revisits.
componentWillMount() {
this.getGroupAccepted();
}
async getGroupAccepted() {
if (this.state.token == null) {
var token = await AsyncStorage.getItem("token");
this.setState({ "token": token });
}
fetch('https://.../api/group/getActive', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: this.state.token
})
})
.then(response => response.json())
.then((data) => {
this.setState({
groups_accepted: data.groups_active,
loading: false,
});
})
.catch((error) => {
console.error(error);
});
}
This is what worked. Now when a user revisits the screen it loads the data once again.
componentDidMount = () => {
this.props.navigation.addListener('didFocus', this._handleDataChange)
}
_handleDataChange = () => {
this.getGroupAccepted();
}