I'm working with Extjs 2.2.1 with Alfresco 3.2 enterprise.
I would like to update the ticket that handles authentication to the alfresco server on components that have been loaded during login. This ticket expires after a set time and this is why I will need to update the ticket.
Options that do not seem viable for me(but please let me know if I'm wrong):
Reload the components to reload the call parameters - I can't do this because it resets whatever the user was previously working on (ie. Tree panel gets reloaded, grid filters reset, etc). The actual webpage never reloads as everything uses ajax calls to update things on the page.
Create a global variable that stores the ticket and attach it as a call parameter with any ajax calls - Any components that were loaded during login will still use the original ticket to make calls to the server.
Try something like this
Ext.onReady(function() {
var token = new Ext.util.MixedCollection();
token.add('id', 'THE_TOKEN_ID');
Ext.ComponentMgr.register('token', token);
});
Attach event listeners to the MixedCollection that updates any components that care about the token.
// now you need all the event listeners
var token = Ext.getCmp('token');
var component = Ext.getCmp('some_component_that_needs_ajax');
token.on('replace', function(key, value, original) {
if(key == 'id') {
component.params.token_id = value; // update the new value
}
});
Whenever the token needs updating, do
var token = Ext.getCmp('token');
token.replace('id', 'THE_NEW_TOKEN_ID');
What's going on here is:
You create a MixedCollection to contain information about your token.
Any components which need to be updated when there is a new token should be updated in the handler for the replace listener for the token MixedCollection.
When you get a new token id, use MixedCollection.replace to update the id key with the new token id.
The replace handler will fire, and the listeners which updates all dependent components.
Related
I have tried to formulate a question title the most generic way that applies to my problem.
I have an Angular application where I have to handle authentication over an external requirement: either use a query string parameter token that has to be exchanged with the server for a JWT, or try to search for a JWT refresh token in the local storage.
It is:
First test the query string: if there is a queryString parameter token, grab the token, delete any JWT in the local storage, exchange the token via API for two JWTs (id_token and refresh_token)
Else go for the refresh token: if there is a refresh_token in the local storage available, exchange it for a JWT id_token via API
Else, if none of the two are available, the user is unauthenticated and a prompt should be displayed
I used Observables almost the correct way
this.queryParamMap$.unsubscribe();
this.queryParamMap$ = this.activatedRoute.queryParamMap
.subscribe(
params => {
let token = params.get('token');
........
if (!!token) {
doLoginWithToken();
else if (isJwtRefreshAvailable())
doLoginWithRefreshToken();
There is one problem with this approach: the very first time the application starts up, the query param map is empty, even if I follow a direct browser link http://localhost:4200?token=AAAAAAAA. I have to wait for the next element which contains the token.
This has two undesirable effects:
At the first attempt, being the token undefined, the application immediately tries to log in with the refresh token
If I filter the queryParamMap observable for a token being present, if a token is never present the observable will never emit, thus not activating the subscription.
My problem can be summarized/generalized as follows.
I have an Observable that I know for sure emits undefined the very first time, but either in no time it could be ready with a proper value, or it won't emit new values after the initial undefined.
Else said, while the observable emits undefined and my code starts reacting to it (e.g. by testing for token), a new value can be ready for emission right away.
How can I solve this in Rxjs? Note that accessing the JWT token from the local storage is a synchronous operation, but it's easy to create Observable.of(localStorage.get(KEY)) which emits immediately if a refresh token is present.
For that, I can't realistically use race operator, because the refresh token is always ready and always wins the race.
How can I write asynchronous code that performs like the steps I described earlier?
As the ultimate result of the authentication, an Observable<UserProfileDto | undefined> emits the information about the user, which is used to display personalized information.
You have 2 problems here:
On init you got "undefined" value (its because probably, under the hood, there is some BehaviourSubject emitting its default value). To overcome this, you can add RxJS operator (skip(1)) to skip that first value, but:
Problem here is if you do not have query values at all, you will not reach your subscribe function. Its because queryParamMap will emit a value only, if there is a change (and in that case there is not):
You can do it without Angular, to just parse url from:
const urlParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlParams.entries());
Or using router in Angular:
this.router.events
// Wait for the navigation end event (since component is initialized before angular router navigation is done)
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe((event: NavigationStart) => {
// Take query params snaphot
const map = this.route.snapshot.queryParams;
});
I have implemented GMail API which gets Emails for me. Now I am trying to add pagination to it I have succeed in getting next records but now I also want to have Previous option(which required previous token).
I am unable to get into it below is what I tried so far.
public function paginate(Request $request){
$label = $request->input("label");
$nextToken = $request->input("next");
$prevToken = $request->input("prev");
$messages = LaravelGmail::message();
$msg = $messages->take(3)->in($label)->all($nextToken);
$nextToken_New = $messages->pageToken;
return view('gmail.load_mails', ['messages' => $msg, 'nextPageToken' => $nextToken_New,
'prevPageToken' => $nextToken]);
}
Now In the above function nextPageToken is passed in view as $nextToken_New
and for prevPageToken I am unable to set previous page token.(In code I have set last nextPageToken to prevPageToken which is not working)
Remember prevPageToken will be used to set on back key.
The Gmail api does not support prevous page token. Its not going to return the value to you.
Your first option would be to save these tokens on your server and then when ever you want to go back a page simply supply the token you want to the page token field
The second option and the one that i personally feel would be the most logical. Would be to cache the data returned by these requests on your server so that
you dont have to make extra http calls to the server.
you are not eating addictal quota making a call you have already made before.
APIs were not meant for you to use to implement pagination in your application. You should only be requesting data once its your job to then cache that data so that you wont need to make the same request twice.
I'm developing my first Nova field. It's an index field that contains a button which sends an Axios request, and when a response is being returned I need to reload the index view.
For now I got this:
this.$router.go(this.$router.currentRoute);
The problem is that it refreshes the entire page (a hard-refresh, like when you press Cmd+R). I just want to reload the current route (which is the index route of a resource).
I also tried this:
this.$router.push({
name: 'index',
params: {
resourceName: this.resourceName,
},
});
But since I pushed the same route, it does nothing.
Any ideas?
Thank's, Daniel.
You can try something like this
let currentFilters = _.cloneDeep(this.$store.state[`${this.resourceName}`]['filters']);
await this.$store.commit(`${this.resourceName}/storeFilters`, {});
await this.$store.commit(`${this.resourceName}/storeFilters`, currentFilters);
This code will reset currently applied filters to empty object and then requests old filters again which leads to resource index updating. But be careful - this method makes two requests to the server.
I'm facing the same issue now while trying to implement custom popup component - but that's all I could do with implemented in Nova vuex store.
Idea of implementation was taken from https://github.com/tanmuhittin/nova-reload-resources/blob/f27da9507a97696b7aca0e9bd7e5afd3001f0891/resources/js/components/Card.vue#L21
Is there a way with Laravel to obtain a new CSRF-token, even when the current token might have expired? I'd like to be able to get a new token without updating the user interface.
I've been experimenting with the Visibility API to check if the browser (only mobile users) gets active again but I soon found out that's not really the issue. If the token has expired, so far I'm unable to get a new one, because I get the token mismatch exception. I want a new token, ignore any mismatch exception, put it in the DOM and let the user continue again.
My user might experience a long idle time but when he/she reactivates the mobile page I want the user to be able to proceed where he/she left off without the need to let them reload the page and provide initial data (like name) again.
You can use this script on pages needed a token refresh without refresh page :
<script type="text/javascript">
var csrfToken = $('[name="csrf_token"]').attr('content');
setInterval(refreshToken, 3600000); // 1 hour
function refreshToken(){
$.get('refresh-csrf').done(function(data){
csrfToken = data; // the new token
});
}
setInterval(refreshToken, 3600000); // 1 hour
</script>
And in your routes/web.php
Route::get('refresh-csrf', function(){
return csrf_token();
});
You can also disable csrf_token verifiction on certain routes, creating a middleware, example below :
https://laracasts.com/discuss/channels/general-discussion/l5-disable-csrf-middleware-on-certain-routes
I want to be able to read / write some variables to the current session in my Salesforce site pages.
I have a site built using Salesforce Sites, I need to store/retrieve some values across all the pages (consider that I am building something similar to a shopping cart).
However I cant find any good example on how to read and write variables to the session (anonymous user).
I am using Visualforce pages with several controllers built in Apex.
Regards
If you are building something like a shopping cart, or a "wizard" where you need to keep controller variables in context from one page view to another, then the best way to do this in VisualForce is to use the same controller.
When the user submits a form ( through actionFunctions, commandButtons, or commandLinks, etc.), and your controller returns a page Reference, the view state is preserved if the new visual force page uses the same controller.
In this way, you could, for example, have the user enter their name and email address using apex:inputField tags on page one. They navigate to page two, which uses the same controller as page one, and the page could reference the same controller variables. Essentially, the controller is still in scope, and so are all the variables that were updates.
Example:
Page one:
<apex:page controller="myController">
Please enter your name <apex:inputText value="{!shopper_name}"/>
<br/>
<apex:commandButton action="{!pageTwo}" value="Click for page two"/>
</apex:page>
Page two:
<apex:page controller="myController">
You entered: <apex:outputText value="{!shopper_name}" />.
</apex:page>
Controller:
public class myController {
public string shopper_name { get; set; }
public myController() {
shopper_name = null;
}
}
Custom settings are cached at the application level, maybe that's why it was suggested in the link above. I'm not sure if I'd recommend that approach, but you might be able to get it to work.
If you create a Custom Setting named "SessionData", and add your custom fields (that represent the data you want to store in session), you could save data to it like this:
Database.SaveResult result = Database.insert(new SessionData__c(YourFieldHere='Your value here etc'));
System.debug(result.getID());
Then use the resulting custom setting ID to store in a cookie. While custom settings can be accessed using normal SOQL, the advantage is that the data is cached and can be accessed like this:
if (SessionData__c.getAll().containsKey('unique ID from cookie here'))
{
System.debug(SessionData__c.getInstance('unique ID from cookie here').YourFieldHere);
}
Keep in mind that custom settings weren't really designed for this, so you'll need to periodically purge old custom settings data, as normal session management systems do.
See the Apex Custom Settings documentation for more details.
I think Visualforce View State might be useful to you:
Visualforce pages that contain a form component also contain an encrypted, hidden form field that encapsulates the view state of the page. This view state is automatically created, and as its name suggests, it holds the state of the page - state that includes the components, field values and controller state.
You should use Javascript cookies for this.
You could also use Apex cookies, but then you'd need to make sure that each request hits the server (and not the caching layer).
for Apex Cookie you can use following code:
//Setting Cookie
public void setCookie() {
Cookie userCookie = new Cookie('CookieName', fieldValueToBeStoredAsCookie, null, 315569260, false); //Here 315569260 represents cookie expiry date = 10 years. You can set this to what ever expiry date you want. Read apex docs for more details.
ApexPages.currentPage().setCookies(new Cookie[] {
userCookie
});
}
//Reading Cookie
Cookie cookie = ApexPages.currentPage().getCookies().get('CookieName');
if (cookie != null) {
String fieldValueToBeStoredAsCookie = cookie.getValue();
}