How to add user authentication with ReactJS Components - reactjs

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

DRF and Knox Authentication: Demo accounts where user doesn't have to input credentials

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))
}

redirecting in react router 6 and reactjs 17

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 test the fetch post request using jest

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.

Unhandled Rejection (TypeError): Cannot read property 'error' of undefined

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

React Native refreshing data

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();
}

Resources