conditional authentication
This commit is contained in:
Родитель
873b5bda1c
Коммит
9590048bc7
|
@ -103,7 +103,7 @@ const router = new express.Router();
|
|||
* A path to enable initializing authentication configuration and add
|
||||
* authentication to middleware pipeline
|
||||
*/
|
||||
router.get('/init', function (req, res) {
|
||||
router.get('/init', (req, res) => {
|
||||
if (!authEnabled) {
|
||||
initializePassport();
|
||||
addAuthRoutes();
|
||||
|
@ -112,15 +112,31 @@ router.get('/init', function (req, res) {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Returning logged in account information
|
||||
*/
|
||||
router.get('/account', (req, res) => {
|
||||
if (!authEnabled) {
|
||||
return res.json({ account: null });
|
||||
}
|
||||
|
||||
if (req.user) {
|
||||
return res.json({ account: req.user });
|
||||
}
|
||||
|
||||
if (req.query.force) {
|
||||
return res.json({ account: null });
|
||||
}
|
||||
|
||||
return setTimeout(() => {
|
||||
return res.redirect(req.originalUrl + '?force=1');
|
||||
}, 7000);
|
||||
});
|
||||
|
||||
/**
|
||||
* Dynamically adding authentication routes once passport is initialized
|
||||
*/
|
||||
function addAuthRoutes() {
|
||||
// Authentications Routes
|
||||
|
||||
// app.get('/account', ensureAuthenticated, function(req, res){
|
||||
// res.render('account', { user: req.user });
|
||||
// });
|
||||
|
||||
router.get('/login',
|
||||
passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import alt, { AbstractActions } from '../alt';
|
||||
import * as request from 'xhr-request';
|
||||
|
||||
interface IAccountActions {
|
||||
failure(error: any): any;
|
||||
updateAccount(): any;
|
||||
}
|
||||
|
||||
class AccountActions extends AbstractActions implements IAccountActions {
|
||||
constructor(alt: AltJS.Alt) {
|
||||
super(alt);
|
||||
}
|
||||
|
||||
updateAccount() {
|
||||
|
||||
return (dispatcher: (account: IDictionary) => void) => {
|
||||
|
||||
request('/auth/account', {
|
||||
json: true
|
||||
},
|
||||
(error: any, result: any) => {
|
||||
|
||||
if (error) {
|
||||
return this.failure(error);
|
||||
}
|
||||
return dispatcher({ account: result.account });
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
failure(error: any) {
|
||||
return { error };
|
||||
}
|
||||
}
|
||||
|
||||
const accountActions = alt.createActions<IAccountActions>(AccountActions);
|
||||
|
||||
export default accountActions;
|
|
@ -8,6 +8,9 @@ import SelectField from 'react-md/lib/SelectFields'
|
|||
import NavigationLink from './NavigationLink'
|
||||
import { Link } from 'react-router';
|
||||
|
||||
import AccountStore from '../../stores/AccountStore';
|
||||
import AccountActions from '../../actions/AccountActions';
|
||||
|
||||
import './style.css';
|
||||
|
||||
const avatarSrc = 'https://cloud.githubusercontent.com/assets/13041/19686250/971bf7f8-9ac0-11e6-975c-188defd82df1.png'
|
||||
|
@ -28,57 +31,75 @@ const drawerHeaderChildren = [
|
|||
position={SelectField.Positions.BELOW}
|
||||
className='md-select-field--toolbar'
|
||||
/>)
|
||||
]
|
||||
];
|
||||
|
||||
export default ({ children = null, title = 'Ibex Dashboard' }) => {
|
||||
export default class Navbar extends React.Component<any, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
var pathname = '/';
|
||||
try { pathname = window.location.pathname; } catch (e) { }
|
||||
this.state = AccountStore.getState();
|
||||
AccountStore.listen((state) => {
|
||||
this.setState(state);
|
||||
});
|
||||
AccountActions.updateAccount();
|
||||
}
|
||||
|
||||
var navigationItems = [
|
||||
<ListItem
|
||||
key='0'
|
||||
component={Link}
|
||||
href='/'
|
||||
active={pathname == '/'}
|
||||
leftIcon={<FontIcon>home</FontIcon>}
|
||||
tileClassName='md-list-tile--mini'
|
||||
primaryText={'Home'}
|
||||
/>,
|
||||
<ListItem
|
||||
key='1'
|
||||
component={Link}
|
||||
href='/about'
|
||||
active={pathname == '/about'}
|
||||
leftIcon={<FontIcon>info</FontIcon>}
|
||||
tileClassName='md-list-tile--mini'
|
||||
primaryText={'About'}
|
||||
/>,
|
||||
<ListItem
|
||||
key='2'
|
||||
component={Link}
|
||||
href='/dashboard'
|
||||
active={pathname == '/dashboard'}
|
||||
leftIcon={<FontIcon>dashboard</FontIcon>}
|
||||
tileClassName='md-list-tile--mini'
|
||||
primaryText={'Dashboard'}
|
||||
/>
|
||||
];
|
||||
render() {
|
||||
let { children, title } = this.props;
|
||||
let pathname = '/';
|
||||
try { pathname = window.location.pathname; } catch (e) { }
|
||||
|
||||
return (
|
||||
<div>
|
||||
<NavigationDrawer
|
||||
navItems={navigationItems}
|
||||
contentClassName='md-grid'
|
||||
drawerHeaderChildren={drawerHeaderChildren}
|
||||
mobileDrawerType={NavigationDrawer.DrawerTypes.TEMPORARY_MINI}
|
||||
tabletDrawerType={NavigationDrawer.DrawerTypes.TEMPORARY_MINI}
|
||||
desktopDrawerType={NavigationDrawer.DrawerTypes.TEMPORARY_MINI}
|
||||
toolbarTitle={title}
|
||||
toolbarActions={null}
|
||||
>
|
||||
{children}
|
||||
</NavigationDrawer>
|
||||
</div>
|
||||
)
|
||||
let navigationItems = [
|
||||
<ListItem
|
||||
key='0'
|
||||
component={Link}
|
||||
href='/'
|
||||
active={pathname == '/'}
|
||||
leftIcon={<FontIcon>home</FontIcon>}
|
||||
tileClassName='md-list-tile--mini'
|
||||
primaryText={'Home'}
|
||||
/>,
|
||||
<ListItem
|
||||
key='1'
|
||||
component={Link}
|
||||
href='/about'
|
||||
active={pathname == '/about'}
|
||||
leftIcon={<FontIcon>info</FontIcon>}
|
||||
tileClassName='md-list-tile--mini'
|
||||
primaryText={'About'}
|
||||
/>,
|
||||
<ListItem
|
||||
key='2'
|
||||
component={Link}
|
||||
href='/dashboard'
|
||||
active={pathname == '/dashboard'}
|
||||
leftIcon={<FontIcon>dashboard</FontIcon>}
|
||||
tileClassName='md-list-tile--mini'
|
||||
primaryText={'Dashboard'}
|
||||
/>
|
||||
];
|
||||
|
||||
let toolbarActions = (
|
||||
<div className='md-subheading-1' style={{ paddingRight: 20 }}>
|
||||
{this.state.account && 'Hello, ' + this.state.account.displayName || ''}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<NavigationDrawer
|
||||
navItems={navigationItems}
|
||||
contentClassName='md-grid'
|
||||
drawerHeaderChildren={drawerHeaderChildren}
|
||||
mobileDrawerType={NavigationDrawer.DrawerTypes.TEMPORARY_MINI}
|
||||
tabletDrawerType={NavigationDrawer.DrawerTypes.TEMPORARY_MINI}
|
||||
desktopDrawerType={NavigationDrawer.DrawerTypes.TEMPORARY_MINI}
|
||||
toolbarTitle={title}
|
||||
toolbarActions={toolbarActions}
|
||||
>
|
||||
{children}
|
||||
</NavigationDrawer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import alt, { AbstractStoreModel } from '../alt';
|
||||
|
||||
import accountActions from '../actions/AccountActions';
|
||||
|
||||
interface IAccountStoreState {
|
||||
account: IDictionary;
|
||||
}
|
||||
|
||||
class AccountStore extends AbstractStoreModel<IAccountStoreState> implements IAccountStoreState {
|
||||
|
||||
account: IDictionary;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.account = null;
|
||||
|
||||
this.bindListeners({
|
||||
updateAccount: accountActions.updateAccount
|
||||
});
|
||||
}
|
||||
|
||||
updateAccount(state: any) {
|
||||
this.account = state.account;
|
||||
}
|
||||
}
|
||||
|
||||
const accountStore = alt.createStore<IAccountStoreState>(AccountStore, 'AccountStore');
|
||||
|
||||
export default accountStore;
|
57
web.config
57
web.config
|
@ -1,57 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This configuration file is required if iisnode is used to run node processes behind
|
||||
IIS or IIS Express. For more information, visit:
|
||||
|
||||
https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
|
||||
<webSocket enabled="false" />
|
||||
<handlers>
|
||||
<!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
|
||||
<add name="iisnode" path="server" verb="*" modules="iisnode" />
|
||||
</handlers>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<!-- Do not interfere with requests for node-inspector debugging -->
|
||||
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
|
||||
<match url="^server\/debug[\/]?" />
|
||||
</rule>
|
||||
|
||||
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
|
||||
<rule name="StaticContent">
|
||||
<action type="Rewrite" url="public{REQUEST_URI}"/>
|
||||
</rule>
|
||||
|
||||
<!-- All other URLs are mapped to the node.js site entry point -->
|
||||
<rule name="DynamicContent">
|
||||
<conditions>
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
|
||||
</conditions>
|
||||
<action type="Rewrite" url="server"/>
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
|
||||
<!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
|
||||
<security>
|
||||
<requestFiltering>
|
||||
<hiddenSegments>
|
||||
<remove segment="bin"/>
|
||||
</hiddenSegments>
|
||||
</requestFiltering>
|
||||
</security>
|
||||
|
||||
<!-- Make sure error responses are left untouched -->
|
||||
<httpErrors existingResponse="PassThrough" />
|
||||
|
||||
<!--
|
||||
This settings will ensure that once the user updates the authentication information
|
||||
the web app with automatically recycle the node.js application and load the new settings
|
||||
-->
|
||||
<iisnode watchedFiles="web.config;server\config.private.js"/>
|
||||
</system.webServer>
|
||||
</configuration>
|
Загрузка…
Ссылка в новой задаче