问题
Im stuck on this one issue trying to rewrite the Web Api SPA template with OAuth (in knockout.js) into angular.js.
When I click an external login button a series of requests take place that eventually result in
Authentication.SignIn(claimsIdentity);
This is good! However, right after I return Ok() I get redirected to the external login (Google). After I signin with Google their authorization servers respond with a 302 redirect to the following location:
http://localhost:59936/access_token=xxxx&token_type=bearer&expires_in=1209600&state=yyyy
Looking at the SPA template in knockout I'm supposed to parse the url for the token, and make a call to getUserInfo() with the access token.
However what happens is that link just gets stuffed into my browser url bar and Angular is oblivious to it. My httpInterceptor does not fire, neither does $routeChanged, and I think it would be silly/dirty/ and probably wont work to make a $routeProvider.when("/access_token")
I'm in 1.2.9 angular (I saw someone mention a bug in angular that i cant find regarding it's http interceptor handling of 302 and that it's fixed in 1.2.9 but does not seem to be the case.
What to do?
EDIT: Actually, thinking about how the code is structured it wouldnt actually be that dirty to be able to catch that using routeProvider. This is because the HomeController looks something like this:
function HomeController(...) {
//Parses the url above
var fragment = getFragment();
... All kinds of fragment checks (fragment.access_token, fragment.state, etc)...
}
The problem is the HomeController does not get instantiated when this URL gets stuffed into the browser.
Is there any way to match the above url to a route? Something like when('/access_token*rest') --However this does not work.
A potential workaround I can think of is to catch the url change in $locationChangeStart and stuff the access_token into local/session storage but this would require a lot of code restructuring since all of the logic is already in the HomeController. The best would be just get it to instantiate when that url gets hit.
Unsatisfactory workaround: Here's another the workaround but Im really not happy with it. It's hackish and requires a lot of restructuring.
app.run(['$rootScope', '$location', '$http', '$controller', 'AuthenticationService',
'$window', 'StorageService', //HomeController Dependencies
function ($rootScope,
$location,
$http,
$controller,
AuthenticationService,
$window, StorageService)
{
$rootScope.$on("$locationChangeStart", function (event, next, current) {
if (next.indexOf("access_token") > -1) {
var homeController = $controller(Controllers.Authentication.HomeController, {
'$rootScope': $rootScope,
'$scope': {},
'$window': $window,
'$location': $location,
'AuthenticationService': AuthenticationService,
'StorageService': StorageService
});
}
});
}
回答1:
Is there any way to match the above url to a route? Something like when('/access_token*rest') --However this does not work.
If your URL were http://localhost:59936/?access_token=xxxx&token_type=bearer&expires_in=1209600&state=yyyy (notice the added ?) then the router could match it like this $routeProvider.when('/') (since the router will ignore the param string) then in your controller you can parse the url parameters.
Is this external login causing the page containing your angular app to redirect to the external webpage? If this is the case, then your app will be unloaded, which probably isn't ideal. To handle external login, I usually open a popup window so that my app doesn't get unloaded.
来源:https://stackoverflow.com/questions/21501305/web-api-oauth-with-angular-front-end-cannot-handle-302-redirect