Oauth2 节点护照授权 header 错误(匿名用户)
Oauth2 Node Passport Authorization header error (Anonymous user)
最近升级了我们连接的 Oauth 2 服务器。为了让我们遵守并获得我们需要对此新服务器进行身份验证的新数据。
以前的服务器使用我即将布置的代码运行良好,但是在我们完全验证并获得一致错误时在新服务器上运行。
这是错误
app.js
所有的护照魔法都发生在这里
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var config = require('./config.js')
var passport = require('passport');
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
var session = require('express-session');
var async = require('async');
var index = require('./routes/index');
var users = require('./routes/users');
var patientdata = require('./routes/patient');
var account = require('./routes/account');
var logout = require('./routes/logout');
var about = require('./routes/about');
// serialize and deserialize
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
// config
passport.use('vendor', new OAuth2Strategy({
authorizationURL: config.vendor.authorizationURL,
tokenURL: config.vendor.tokenURL,
clientID: config.vendor.clientID,
clientSecret: config.vendor.clientSecret,
callbackURL: config.vendor.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
// store access token
req.session.accessToken=accessToken;
return done(null, profile);
});
}
));
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({secret: 'secretword'}))
app.use(passport.initialize());
app.use(passport.session());
app.get('/', index.execute);
app.get('/users', users.execute);
app.get('/account', ensureAuthenticated, account.execute);
app.get('/logout', logout.execute);
// vendor
app.get('/auth/vendor',
passport.authenticate('vendor'),
function(req, res){
});
app.get('/auth/vendor/callback',
passport.authenticate('vendor', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/account');
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/')
}
module.exports = app;
URL、ID、机密等信息正确,供应商正在验证。
我们似乎已通过 Oauth2 服务器的身份验证,并且我们正在获得批准的令牌,但我们在他们的日志中显示为 "anonymous" 用户。
这是供应商方面的日志文件。
我的应用程序尝试进行身份验证的服务器日志
-- Us starting request for token
...
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@77bd892d
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/logout'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faab5ec: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffc434: RemoteIpAddress: 68.46.8.80; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
Break -- returns anonymous
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/token'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faab5ec: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffc434: RemoteIpAddress: 68.46.8.80; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@73821302, returned: -1
09:43:47.975 [http-nio-8282-exec-2] DEBUG o.s.b.a.audit.listener.AuditListener - AuditEvent [timestamp=Thu Mar 24 09:43:47 CDT 2016, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]
09:43:47.975 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
...
我要求供应商使用他们制作的测试应用程序登录并向我发送日志,请看下面他们有一个 "Basic authentication header"
供应商管理应用认证的服务器日志
Break -- Starting admin request for token
...
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@77bd892d
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/logout'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
10:07:48.562 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Basic Authentication Authorization header found for user ' admin'
10:07:48.562 [http-nio-8282-exec-3] DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
10:07:48.563 [http-nio-8282-exec-3] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'scopedTarget.clientDetailsService'
10:07:48.564 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@36677da1: Principal: org.springframework.security.core.userdetails.User@664f353: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 66.41.28.185; SessionId: null; Granted Authorities: ROLE_CLIENT
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@36677da1: Principal: org.springframework.security.core.userdetails.User@664f353: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 66.41.28.185; SessionId: null; Granted Authorities: ROLE_CLIENT'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.s.CompositeSessionAuthenticationStrategy - Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy@285827ac
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/token'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@36677da1: Principal: org.springframework.security.core.userdetails.User@664f353: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 66.41.28.185; SessionId: null; Granted Authorities: ROLE_CLIENT
10:07:48.581 [http-nio-8282-exec-3] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@73821302, returned: 1
10:07:48.581 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful
...
我们知道我们没有发送 "Authorization: BASIC (RANDOMCODE)" 但我们无法手动将其注入。我的印象是 passport 为我们做了这件事,但事实并非如此。
最后我们回去检查了旧服务器并确认我们之前从未在 header 中发送过此 BASIC 代码。我不确定服务器以前怎么从来没有发现这个,但我们需要尽快升级,并且一直在研究如何让它工作。
因此,对于 OAuth2,预期的令牌 header 是一个授权:承载 header。您可以在此处查看:规范文档中的 https://www.rfc-editor.org/rfc/rfc6750#section-2.1。
在这种情况下,如果供应商正在寻找 Basic header,那他们就错了。在幕后 passport.js oauth2 策略正在利用以下 node.js 模块:https://github.com/ciaranj/node-oauth
要真正开始更深入地研究这个问题,您可能希望手动实施一个示例,以查看事情“卡住”的地方。但是,通过查看此内容,您可以将 header 从不记名令牌更改为 node-oauth 库中的基本令牌:https://github.com/ciaranj/node-oauth/blob/master/lib/oauth2.js#L15
为此,我们需要更改一些代码并访问一些可能更容易更改的区域,因为我们正在访问内部属性。
首先,改变策略将其压入变量:
var oauthStrategy = new OAuth2Strategy({
authorizationURL: config.vendor.authorizationURL,
tokenURL: config.vendor.tokenURL,
clientID: config.vendor.clientID,
clientSecret: config.vendor.clientSecret,
callbackURL: config.vendor.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
// store access token
req.session.accessToken=accessToken;
return done(null, profile);
});
}
);
然后,我们需要访问“受保护的”属性(它并没有真正受到保护,因为 javascript 无法强制执行)- 有关更多信息,请参见:https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L91.
oauthStrategy._oauth2.setAuthMethod('BASIC');
现在整理攻略:
passport.use('vendor', oauthStrategy);
我还没有实际测试过这个,但是通过查看源代码,这应该对你有用,或者至少让你走上正确的道路。
Mwillbank,您所解决的问题是正确的,但这里的问题是在不同的领域。我在这个问题上与供应商合作。问题出在 authorization_code 流程期间对授权服务器的 getAccessToken 调用中的授权 header。您引用的标准是关于如何在拥有访问令牌后从资源服务器请求数据。对于那个电话,你是绝对正确的,我们按照你提到的那样实施该标准。 OAuth2标准适用于我们情况的部分是Section 4.1.3 of the main standard (rfc6749). This section references Section 3.2.1 on Client Authentication, which in turn references Section 2.3, also on Client Authentication。在这里,您将看到机密客户端的客户端身份验证没有强制性标准。但是,在下一页的 2.3.1 中给出的一个示例是使用基本身份验证。我相信这是在 authorization_code 流程的 getAccessToken 调用期间对客户端进行身份验证的默认且最常用的方法。
可能部分问题是 passport.js 假设这种情况涉及移动应用程序和 Web 服务器之间的 implicit_grant 流,其中没有对 getAccessToken 的单独调用。我注意到您在链接中 post 发表评论说护照实施主要是 OAuth1,对 OAuth2 的支持参差不齐。也许我们 运行 进入了那些错过的地方之一。尽管如此,我发现您的 post 有助于更好地理解护照的工作原理。谢谢
最近升级了我们连接的 Oauth 2 服务器。为了让我们遵守并获得我们需要对此新服务器进行身份验证的新数据。
以前的服务器使用我即将布置的代码运行良好,但是在我们完全验证并获得一致错误时在新服务器上运行。
这是错误
app.js
所有的护照魔法都发生在这里
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var config = require('./config.js')
var passport = require('passport');
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
var session = require('express-session');
var async = require('async');
var index = require('./routes/index');
var users = require('./routes/users');
var patientdata = require('./routes/patient');
var account = require('./routes/account');
var logout = require('./routes/logout');
var about = require('./routes/about');
// serialize and deserialize
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
// config
passport.use('vendor', new OAuth2Strategy({
authorizationURL: config.vendor.authorizationURL,
tokenURL: config.vendor.tokenURL,
clientID: config.vendor.clientID,
clientSecret: config.vendor.clientSecret,
callbackURL: config.vendor.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
// store access token
req.session.accessToken=accessToken;
return done(null, profile);
});
}
));
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({secret: 'secretword'}))
app.use(passport.initialize());
app.use(passport.session());
app.get('/', index.execute);
app.get('/users', users.execute);
app.get('/account', ensureAuthenticated, account.execute);
app.get('/logout', logout.execute);
// vendor
app.get('/auth/vendor',
passport.authenticate('vendor'),
function(req, res){
});
app.get('/auth/vendor/callback',
passport.authenticate('vendor', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/account');
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/')
}
module.exports = app;
URL、ID、机密等信息正确,供应商正在验证。
我们似乎已通过 Oauth2 服务器的身份验证,并且我们正在获得批准的令牌,但我们在他们的日志中显示为 "anonymous" 用户。
这是供应商方面的日志文件。
我的应用程序尝试进行身份验证的服务器日志
-- Us starting request for token
...
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@77bd892d
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/logout'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faab5ec: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffc434: RemoteIpAddress: 68.46.8.80; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
Break -- returns anonymous
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/token'
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faab5ec: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffc434: RemoteIpAddress: 68.46.8.80; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
09:43:47.974 [http-nio-8282-exec-2] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@73821302, returned: -1
09:43:47.975 [http-nio-8282-exec-2] DEBUG o.s.b.a.audit.listener.AuditListener - AuditEvent [timestamp=Thu Mar 24 09:43:47 CDT 2016, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]
09:43:47.975 [http-nio-8282-exec-2] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
...
我要求供应商使用他们制作的测试应用程序登录并向我发送日志,请看下面他们有一个 "Basic authentication header"
供应商管理应用认证的服务器日志
Break -- Starting admin request for token
...
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@77bd892d
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/logout'
10:07:48.560 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
10:07:48.562 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Basic Authentication Authorization header found for user ' admin'
10:07:48.562 [http-nio-8282-exec-3] DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
10:07:48.563 [http-nio-8282-exec-3] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'scopedTarget.clientDetailsService'
10:07:48.564 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@36677da1: Principal: org.springframework.security.core.userdetails.User@664f353: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 66.41.28.185; SessionId: null; Granted Authorities: ROLE_CLIENT
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@36677da1: Principal: org.springframework.security.core.userdetails.User@664f353: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 66.41.28.185; SessionId: null; Granted Authorities: ROLE_CLIENT'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.s.CompositeSessionAuthenticationStrategy - Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy@285827ac
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.security.web.FilterChainProxy - /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth/token'; against '/oauth/token'
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
10:07:48.580 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@36677da1: Principal: org.springframework.security.core.userdetails.User@664f353: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CLIENT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 66.41.28.185; SessionId: null; Granted Authorities: ROLE_CLIENT
10:07:48.581 [http-nio-8282-exec-3] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@73821302, returned: 1
10:07:48.581 [http-nio-8282-exec-3] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful
...
我们知道我们没有发送 "Authorization: BASIC (RANDOMCODE)" 但我们无法手动将其注入。我的印象是 passport 为我们做了这件事,但事实并非如此。
最后我们回去检查了旧服务器并确认我们之前从未在 header 中发送过此 BASIC 代码。我不确定服务器以前怎么从来没有发现这个,但我们需要尽快升级,并且一直在研究如何让它工作。
因此,对于 OAuth2,预期的令牌 header 是一个授权:承载 header。您可以在此处查看:规范文档中的 https://www.rfc-editor.org/rfc/rfc6750#section-2.1。
在这种情况下,如果供应商正在寻找 Basic header,那他们就错了。在幕后 passport.js oauth2 策略正在利用以下 node.js 模块:https://github.com/ciaranj/node-oauth
要真正开始更深入地研究这个问题,您可能希望手动实施一个示例,以查看事情“卡住”的地方。但是,通过查看此内容,您可以将 header 从不记名令牌更改为 node-oauth 库中的基本令牌:https://github.com/ciaranj/node-oauth/blob/master/lib/oauth2.js#L15
为此,我们需要更改一些代码并访问一些可能更容易更改的区域,因为我们正在访问内部属性。
首先,改变策略将其压入变量:
var oauthStrategy = new OAuth2Strategy({
authorizationURL: config.vendor.authorizationURL,
tokenURL: config.vendor.tokenURL,
clientID: config.vendor.clientID,
clientSecret: config.vendor.clientSecret,
callbackURL: config.vendor.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
// store access token
req.session.accessToken=accessToken;
return done(null, profile);
});
}
);
然后,我们需要访问“受保护的”属性(它并没有真正受到保护,因为 javascript 无法强制执行)- 有关更多信息,请参见:https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L91.
oauthStrategy._oauth2.setAuthMethod('BASIC');
现在整理攻略:
passport.use('vendor', oauthStrategy);
我还没有实际测试过这个,但是通过查看源代码,这应该对你有用,或者至少让你走上正确的道路。
Mwillbank,您所解决的问题是正确的,但这里的问题是在不同的领域。我在这个问题上与供应商合作。问题出在 authorization_code 流程期间对授权服务器的 getAccessToken 调用中的授权 header。您引用的标准是关于如何在拥有访问令牌后从资源服务器请求数据。对于那个电话,你是绝对正确的,我们按照你提到的那样实施该标准。 OAuth2标准适用于我们情况的部分是Section 4.1.3 of the main standard (rfc6749). This section references Section 3.2.1 on Client Authentication, which in turn references Section 2.3, also on Client Authentication。在这里,您将看到机密客户端的客户端身份验证没有强制性标准。但是,在下一页的 2.3.1 中给出的一个示例是使用基本身份验证。我相信这是在 authorization_code 流程的 getAccessToken 调用期间对客户端进行身份验证的默认且最常用的方法。
可能部分问题是 passport.js 假设这种情况涉及移动应用程序和 Web 服务器之间的 implicit_grant 流,其中没有对 getAccessToken 的单独调用。我注意到您在链接中 post 发表评论说护照实施主要是 OAuth1,对 OAuth2 的支持参差不齐。也许我们 运行 进入了那些错过的地方之一。尽管如此,我发现您的 post 有助于更好地理解护照的工作原理。谢谢