I have this Javascript code to handle ActiveDirectory authentication.
I need to create a React component that uses this code, what is the best way to achieve this in React?
var config = { url: 'ldap://compandomain.com:389',
baseDN: 'dc=domainname,dc=com',
username: 'user',
password: 'pass' };
var ad = new ActiveDirectory(config);
var username = 'john.smith#domain.com';
var password = 'password';
ad.authenticate(username, password, function(err, auth) {
if (err) {
console.log('ERROR: '+JSON.stringify(err));
return;
}
if (auth) {
console.log('Authenticated!');
}
else {
console.log('Authentication failed!');
}
});
The React component looks like this:
export default class ActiveDirectory extends React.Component {
..
......
.........
render() {
return <div ..../>;
}
}
you should be abler to handle this authentication in the componentDidMount lifecycle method. it should probably look like this.
import React from 'react';
import ActiveDirectory from 'activedirectory';
export default class ActiveDirectoryComponent extends React.Component {
state = {
authResponse: undefined
};
componentDidMount() {
var config = {
url: 'ldap://compandomain.com:389',
baseDN: 'dc=domainname,dc=com',
username: 'user',
password: 'pass'
};
var ad = new ActiveDirectory(config);
var username = 'john.smith#domain.com';
var password = 'password';
ad.authenticate(username, password, function (err, auth) {
if (err) {
this.setState({ authResponse: { error: JSON.stringify(err) } });
return;
}
if (auth) {
this.setState({ authResponse: auth });
} else {
console.log('Authentication failed!');
this.setState({ authResponse: { authFailed: true } });
}
});
}
render() {
if (!this.state.authResponse) {
return <div>Authenticating....</div>;
}
if (this.state.authResponse.error) {
return <div>{this.state.authResponse.error}</div>
}
if (this.state.authResponse.authFailed) {
return <div>Authentication Failed</div>
}
return <div>.....</div>
}
}
Related
I have added authorization to my Nuxt app, but something is wrong. When i enter wrong password or email, I am still redirected to the main page of the application, although I have to stay on the authorization page and try to log in again.
Here is my code:
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
signOut
} from 'firebase/auth'
export default {
data() {
return {
snackBar: false,
snackBarText: 'No Error Message',
auth: {
email: '',
password: ''
}
}
},
methods: {
login() {
let that = this
this.$fire.auth.signInWithEmailAndPassword(this.auth.email, this.auth.password)
.catch(function (error) {
console.log(error.message);
that.snackBarText = error.message
that.snackBar = true
// $nuxt.$router.push('/login')
}).then((user) => {
console.log(user);
$nuxt.$router.push('/')
})
}
}
}
middleware:
export default function ({ app, route, redirect }) {
if (route.path !== '/login') {
// we are on the protected route
if (!app.$fire.auth.currentUser) {
// take them to sign in in a page
return redirect('/login')
}
} else if (route.path === '/login') {
if (!app.$fire.auth.currentUser) {
// leave them on the sign in page
} else {
return redirect('/')
}
}
}
store:
const state = () => ({
user: null,
};
const mutations = {
SET_USER(state, user) {
state.user = user
},
}
const actions = {
async onAuthStateChangedAction(context, { authUser, claims }) {
if (!authUser) {
context.commit('SET_USER', null)
this.$router.push({
path: '/login'
})
} else {
const { uid, email } = authUser;
context.commit('SET_USER', {
uid,
email
})
}
}
}
const getters = {
getUser(state) {
return state.user
}
}
export default {
state,
actions,
mutations,
getters,
}
Form for authorization is in component popup, which is sent to page login.vue
AuthService.js
import axios from 'axios';
const GET_AUTH_API_BASE_URL = "http://localhost:8087/auth";
class AuthService {
login(user){
return axios.post(GET_AUTH_API_BASE_URL+"/login",user);
}
getRole(userName,password){
return axios.get(GET_AUTH_API_BASE_URL+"/role/"+userName+"/"+password);
}
}
export default new AuthService();
LoginComponent.js
class LoginUserComponent extends Component {
constructor(props) {
super(props);
this. State = {
userName: "",
password: "",
};
this.changeHandler = this.changeHandler.bind(this);
this.login = this.login.bind(this);
}
changeHandler(event) {
this.setState({ [event.target.name]: event.target.value });
// console.log(this.state.user.userName);
}
login(event) {
let userDet = {
userName: this.state.userName,
password: this.state.password,
};
console.log(userDet);
AuthService.login(userDet).then(
(res) => {
sessionStorage.setItem("token", res.data);
AuthService.getRole(userDet).then((res) => {
sessionStorage.setItem("role", res.data);
});
if (sessionStorage.getItem("role") === "Admin") {
console.log("Admin");
this.props.navigate("/employees");
}
if (sessionStorage.getItem("role") === "User") {
console.log("User");
this.props.navigate("/add-employee");
}
},
(error) => {
const resMessage =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
alert(resMessage);
}
);
event.preventDefault();
}
RegisterComponent.js
class RegisterUserComponent extends Component {
constructor(props) {
super(props)
this.state ={
userId:0,
userName:'',
password:'',
role:{
roleId:0,
roleName:''
}
}
this.changeHandler=this.changeHandler.bind(this);
}
changeHandler(event){
this.setState({[event.target.name]:event.target.value});
// console.log(this.state.user.userName);
}
submitData=(event)=>{
console.log(this.state.user);
let userDet={
userId:this.state.userId,
userName:this.state.userName,
password:this.state.password,
role:{
roleId:this.state.roleId,
roleName:this.state.roleName
}
}
console.log(userDet);
// axios.defaults.headers.post['Access-Control-Allow-Origin'] = '*';
axios.post('http://localhost:8087/auth/users',userDet);
event.preventDefault();
this.props.navigate("/")
}
I can able to register a user with role like admin,user.But when I login the registered user, I am getting a axios error as http://localhost:8087/auth/role/[object%20Object]/undefined. My token is storing in session storage but the role(key, value) is not storing.
I have now added my register component. Kindly rectify
Issue
getRole takes two arguments, userName and password
getRole(userName, password) {
return axios.get(GET_AUTH_API_BASE_URL + "/role/" + userName + "/" + password);
}
but the UI is passing a single object
let userDet = {
userName: this.state.userName,
password: this.state.password,
};
...
AuthService.getRole(userDet)
.then((res) => {
sessionStorage.setItem("role", res.data);
});
userName is an object and password is undefined in the getRole function.
Solution
Pass two args.
const { userName, password } = this.state;
...
AuthService.getRole(userName, password)
.then((res) => {
sessionStorage.setItem("role", res.data);
});
I am trying to make a site in Vue and backend on Spring. I want to use rsocket to transfer data, but as soon as I add rsocket seurity in spring, I get :
'metadata is malformed'
Would like to take a look at a working example using jwt/simpleauth
I solved the issue with Simple Auth, now I would like to synchronize this authorization with spring websecurity.
Those. so that routing in rsocket checks authorization via websecurity. I know that this can be implemented through the jwt token, i.e. send a jwt token to a client via rest, but how can I do this in code? JS client (browser) and Spring, how do I generate userdetails token?
Just in case, I'll leave an example of the simpleauth implementation:
// METADATA BUILDER
import {encodeRoute, encodeBearerAuthMetadata, encodeSimpleAuthMetadata, encodeAndAddCustomMetadata, encodeAndAddWellKnownMetadata, MESSAGE_RSOCKET_ROUTING, MESSAGE_RSOCKET_AUTHENTICATION} from "rsocket-core";
export default class Metadata {
constructor(json) {
this.route = json['route'];
this.auth = json['auth'];
}
toMetadata() {
let metadata = Buffer.alloc(0);
if (this.auth) {
if (this.auth["type"] === 'bearer') {
metadata = encodeAndAddCustomMetadata(
metadata,
MESSAGE_RSOCKET_AUTHENTICATION.string,
encodeBearerAuthMetadata(this.auth["token"]),
);
}
if (this.auth["type"] === 'simple') {
metadata = encodeAndAddCustomMetadata(
metadata,
MESSAGE_RSOCKET_AUTHENTICATION.string,
encodeSimpleAuthMetadata(this.auth["username"], this.auth["password"]),
);
}
}
if (this.route) {
metadata = encodeAndAddWellKnownMetadata(
metadata,
MESSAGE_RSOCKET_ROUTING,
encodeRoute(this.route)
);
}
return metadata;
}
}
// RSOCKET CLIENT CLASS
import RSocketWebSocketClient from "rsocket-websocket-client";
import {BufferEncoders, MESSAGE_RSOCKET_COMPOSITE_METADATA, RSocketClient,toBuffer} from "rsocket-core";
import Metadata from "./metadata";
export default class SpringClient {
constructor(wsUrl, keepAlive = 60000, lifetime = 180000, dataMimeType = "application/json") {
this.client = new RSocketClient({
"setup": {
"keepAlive": keepAlive,
"lifetime": lifetime,
"dataMimeType": dataMimeType,
"metadataMimeType": MESSAGE_RSOCKET_COMPOSITE_METADATA.string
},
"transport": new RSocketWebSocketClient({
"url": wsUrl
}, BufferEncoders)
});
}
bearerAuth(token) {
this.auth = {type: "bearer", token: token}
}
simpleAuth(username, password) {
this.auth = {type: "simple", username: username, password: password}
}
logout() {
this.auth = null;
}
connect(
completeCallback = (socket) => {
}, errorCallback = (error) => {
}, subscribeCallback = (cancel) => {
}
) {
this.client.connect().subscribe({
onComplete: socket => {
this.socket = socket;
completeCallback(socket);
},
onError: error => {
errorCallback(error);
},
onSubscribe: cancel => {
subscribeCallback(cancel);
}
});
}
requestResponse(data, route,
completeCallback = (data) => {
},
errorCallback = (error) => {
},
subscribeCallback = (cancel) => {
}
) {
if (this.socket) {
const metadata = new Metadata({
route: route,
auth: this.auth
}).toMetadata();
data = toBuffer(data);
this.socket.requestResponse({
data,
metadata
}).subscribe({
onComplete: data => {
completeCallback(data);
},
onError: error => {
errorCallback(error);
},
onSubscribe: cancel => {
subscribeCallback(cancel);
}
});
}
}
}
// EXAMPLE, HOW TO USE
import SpringClient from "./springclient";
this.client = new SpringClient("ws://localhost:7000/", 5000, 15000, "text/plain");
this.client.connect(
(socket) => {
console.log("got connection complete");
this.socket = socket;
},
(error) => {
console.log("got connection error");
console.error(error);
},
(cancel) => {
console.log("got connection subscribe");
/* call cancel() to abort */
}
)
this.client.simpleAuth("LOGIN", "PASSWORD");
this.client.requestResponse("MESSAGE", "ROUTE",
(data) => {
console.log("got response with requestResponse");
console.log(data.data);
},
(error) => {
console.log("got error with requestResponse");
console.error(error);
},
(cancel) => {
console.log(message);
/* call cancel() to stop onComplete/onError */
}
);
I do not know how to implement a method in which when using the updateProfile () function, it checks the firestore if such mail already exists and then an error would pop up. I did a test method in MyAccount.vue, but it doesn't work, if I don't type anything and click, nothing updates, but that's not the point, I would like it to check if such mail exists.
./src/views/MyAccount.vue
import { mapState } from 'vuex';
export default {
data() {
return {
user: {
username: '',
email: '',
password: ''
}
};
},
computed: {
...mapState(['userProfile']),
},
methods: {
updateProfile() {
this.$store.dispatch('updateProfile', {
username:
this.user.username !== ''
? this.user.username
: this.userProfile.username,
email:
this.user.email !== ''
? this.user.email
: this.userProfile.email,
password:
this.user.password !== ''
? this.user.password
: this.userProfile.password
});
this.user.username = '';
this.user.email = '';
this.user.password = '';
this.showSuccess = true;
setTimeout(() => {
this.showSuccess = false;
}, 2000);
}
}
};
</script>
./src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import * as fb from '../firebase';
import router from '../router/index';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
userProfile: {},
notes: []
},
mutations: {
setUserProfile(state, val) {
state.userProfile = val;
},
setNotes(state, val) {
state.notes = val;
}
},
actions: {
async updateProfile({ commit, dispatch }, user) {
const userId = fb.auth.currentUser.uid;
await fb.usersCollection.doc(userId).update({
username: user.username,
email: user.email,
password: user.password
});
dispatch('fetchUserProfile', { uid: userId });
},
async fetchUserProfile({ commit }, user) {
// fetch user profile
const userProfile = await fb.usersCollection.doc(user.uid).get();
// set user profile in state
commit('setUserProfile', userProfile.data());
// change router to dashboard
if (router.currentRoute.path === '/login') {
router.push('/');
}
}
},
modules: {}
});
export default store;
Before updating, try this:
const current = await fb.usersCollection.where('email', '==', user.email).get()
if (current.empty === true) {
// You are free to do the update, because the email is not in use already
}
Of course, this works best if you make sure to alway lowercase your emails before querying or storing them in the database
I'm working on a component that takes care of registering my users to Sinch (voip platform). In order for my registration to work I need to have some variables that are accessible throughout my component methods. I'm wondering how this should be done using vue.
I need my variable sinchClient to be accessible in my methods newUserRequest() and loginRequest()
Any tips?
Sinch variable
var sinchClient = new SinchClient({
applicationKey: "My-Key",
capabilities: {
messaging: true,
calling: true
},
supportActiveConnection: true,
onLogMessage: function(msg) {
console.log(msg);
}
});
Methods
<script>
export default {
data() {
return {
username: null,
name: null,
password: null,
loggedIn: false
};
},
mounted() {},
methods: {
newUserRequest() {
console.log(this.name, this.password);
if (this.name && this.password) {
var handleSuccess = () => {
console.log("User created");
this.loggedIn = true;
this.name = sinchClient.user.userId;
};
var handleFail = error => {
console.log(error.message);
};
var signUpObject = { username: this.name, password: this.password };
sinchClient
.newUser(signUpObject)
.then(sinchClient.start.bind(sinchClient))
.then(() => {
localStorage[
"sinchSession-" + sinchClient.applicationKey
] = JSON.stringify(sinchClient.getSession());
})
.then(handleSuccess)
.fail(handleFail);
}
},
logInRequest() {
if (this.name && this.password) {
var handleSuccess = () => {
console.log("User logged in");
this.loggedIn = true;
this.name = sinchClient.user.userId;
};
var handleFail = error => {
console.log(error.message);
};
var signUpObject = { username: this.name, password: this.password };
sinchClient
.start(signUpObject)
.then(() => {
localStorage[
"sinchSession-" + sinchClient.applicationKey
] = JSON.stringify(sinchClient.getSession());
})
.then(handleSuccess)
.fail(handleFail);
}
}
}
};
</script>
You can define sinchClient globally and access it using window (window.sinchClient). Better you can create a Vue plugin and inject it in the app context:
var sinchClient = new SinchClient({
applicationKey: "My-Key",
capabilities: {
messaging: true,
calling: true
},
supportActiveConnection: true,
onLogMessage: function(msg) {
console.log(msg);
}
})
Vue.use({
install: function(Vue) {
Object.defineProperty(Vue.prototype, '$sinchClient', {
get () { return sinchClient }
})
}
})
And access it with this.$sinchClientin Vue context