反应 axios 401 未经授权
Posted
技术标签:
【中文标题】反应 axios 401 未经授权【英文标题】:React axios 401 unauthorized 【发布时间】:2019-07-10 20:10:27 【问题描述】:我在尝试对用户进行身份验证时收到 401 错误。只是为了给出上下文,React 正在使用 Express 服务器,并使用 Passport 进行身份验证。 React 的端口是8001
,Express 服务器的端口是8000
。
GET /api/users/user 401 2.167 毫秒 - 59
其他获取请求确实有效。例如
反应
export const getUser = () =>
return async (dispatch) =>
Axios.get('/api/users/user')
.then( (res) =>
console.log(res.data);
localStorage.setItem('auth', res.data.authenticated);
dispatch(type: GET_USER, res);
).catch( (err) =>
console.log(err);
)
axios
import Axios from 'axios'
let AxiosInstance = Axios.create(
baseURL: process.env.REACT_APP_BASE_URL, // http://localhost:8000
withCredentials: true,
headers:
'Content-Type': 'application/json',
,
)
// AxiosInstance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
AxiosInstance.interceptors.response.use(function(response)
return response;
)
export default AxiosInstance
路线/用户
router.get('/user', (req, res, next) =>
if(req.user)
return res.status(200).json(
user: req.user,
authenticated: true
);
else
return res.status(401).json(
error: 'User is not authenticated',
authenticated: false
);
);
文件app.js
var express = require('express');
var app = express();
var userRoute = require('./routes/users');
var postRoute = require('./routes/posts');
var bodyParser = require('body-parser');
var logger = require('morgan');
var models = require('./models');
var User = require('./models/user');
var session = require('express-session');
var cookieParser = require('cookie-parser') ;
var cookieSession = require('cookie-session');
var dotenv = require('dotenv');
var env = dotenv.config();
var cors = require('cors');
const port = process.env.PORT || 8000;
const passport = require('passport');
const path = require('path');
const allowOrigin = process.env.ALLOW_ORIGIN || '*'
// CORS Middleware
if (!process.env.PORT)
require('dotenv').config()
if (!process.env.PORT)
console.log('[api][port] 8000 set as default')
console.log('[api][header] Access-Control-Allow-Origin: * set as default')
else
console.log('[api][node] Loaded ENV vars from .env file')
console.log(`[api][port] $process.env.PORT`)
console.log(`[api][header] Access-Control-Allow-Origin: $process.env.ALLOW_ORIGIN`)
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded( extended: false ));
app.use(cors(
origin: process.env.ALLOW_ORIGIN,
credentials: true,
allowedHeaders: 'X-Requested-With, Content-Type, Authorization',
methods: 'GET, POST, PATCH, PUT, POST, DELETE, OPTIONS'
))
app.use(session(
secret : 'nodeauthsecret',
resave: false,
saveUninitialized: true,
));
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
require('./config/passport-github')(passport);
app.use(function(req, res, next)
res.locals.user = req.user; // This is the important line
console.log(res.locals.user);
next();
);
// app.use(function(req, res, next)
// res.setHeader("Access-Control-Allow-Origin", "*");
// res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// );
app.use('/api/users', userRoute )
app.use('/api/posts', postRoute )
app.listen(port, () =>
console.log('[api][listen] http://localhost:' + port)
)
passport.js
const BCRYPT_SALT_ROUNDS = 12;
const passport = require('passport'),
bcrypt = require('bcrypt'),
JWTstrategy = require('passport-jwt').Strategy,
ExtractJWT = require('passport-jwt').ExtractJwt,
Sequelize = require('sequelize'),
Op = Sequelize.Op;
module.exports = function(passport, user)
const models = require( '../models/index');
const localStrategy = require('passport-local').Strategy;
// serialize session, only store user id in the session information
passport.serializeUser(function(user, done)
done(null, user.id);
);
// from the user id, figure out who the user is...
passport.deserializeUser(function(userId, done)
models.User
.find( where: id: userId )
.then(function(user)
done(null, user);
).catch(function(err)
done(err, null);
);
);
passport.use(
'register',
new localStrategy(
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true,
session: false,
,
(req, username, password, done) =>
try
models.User.findOne(
where:
[Op.or]: [
username: username,
,
email: req.body.email ,
],
,
).then(user =>
if (user != null)
console.log('username or email already taken');
return done(null, false,
message: 'username or email already taken',
);
else
bcrypt.hash(password, BCRYPT_SALT_ROUNDS).then(hashedPassword =>
models.User.create(
username: req.body.username,
password: hashedPassword,
email: req.body.email
).then(user =>
console.log('user created');
return done(null, user);
);
);
);
catch (err)
done(err);
,
),
);
passport.use(
'login',
new localStrategy(
usernameField: 'username',
passwordField: 'password',
session: false
,
(username, password, done, req) =>
try
models.User.findOne(
where:
[Op.or]: [
username: username,
],
,
).then(user =>
if (user === null)
return done(null, false, message: 'Username doesn\'t exist' );
else
bcrypt.compare(password, user.password).then(response =>
if (response !== true)
console.log('passwords do not match');
return done(null, false, message: 'passwords do not match' );
console.log('user found & authenticated');
// note the return needed with passport local - remove this return for passport JWT
return done(null, user);
);
);
catch (err)
done(err);
,
),
);
const opts =
jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('JWT'),
secretOrKey: process.env.jwtsecret,
;
passport.use(
'jwt',
new JWTstrategy(opts, (jwt_payload, done) =>
try
models.User.findOne(
where:
username: jwt_payload._id,
,
).then(user =>
if (user)
console.log('user found in db in passport');
// note the return removed with passport JWT - add this return for passport local
done(null, user);
// console.log(user);
else
console.log('user not found in db');
done(null, false);
);
catch (err)
done(err);
),
);
【问题讨论】:
【参考方案1】:您正面临这个问题,因为您的 req.user
是空的,这就是它转到 else
语句并返回您要返回的 Unauthorized
的原因。
检查您的服务器控制台是否正在打印任何内容console.log(res.locals.user);
发送您的auth token
带有这样的标题
headers :
'Content-Type' : 'application/json',
'Accept' : 'application/json',
'Authorization' : 'Bearer <token_here>'
更新
您的请求将始终返回401 unauthorized
。
https://github.com/manjurulhoque/nodejs-ecommerce-api/blob/master/routes/users.js#L105
检查我的代码。要获得登录用户,您必须使用
passport.authenticate('jwt', session: false )
【讨论】:
res.locals.user 中没有显示任何内容,它曾经可以工作,但我更改了 react 前端的代理设置。它使用jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('JWT')
我的下一个问题是我将如何将令牌从 express 传递以做出反应,以便我可以将其插入 Bearer 旁边?
您必须将令牌从 react 传递给 express,express 将检查过期日期并使用该令牌返回用户。
我更新了上面的代码,并以相反的方式设置它。我有点困惑,我将使用您的解决方案来解决这个问题。谢谢。
我认为你做错了。 Token
应该从客户端发送到服务器。而你的保存在 localStorage 中。服务器将验证令牌并发送您所需的信息。【参考方案2】:
我认为您需要在标题中设置Authorization
,如MDN中所述
HTTP 授权请求标头包含用于 使用服务器验证用户代理,通常在服务器完成之后 回复
401 Unauthorized status
和 WWW-Authenticate 标题。
let ExtractJwt = passportJWT.ExtractJwt;
let Strategy = passportJWT.Strategy;
let opts =
opts.secretOrKey= cfg.jwtSecret
opts.jwtFromRequest= ExtractJwt.fromAuthHeaderWithScheme(cfg.authScheme)
new JWTstrategy(
...
return
initialize: function()
return passport.initialize();
,
authenticate: function()
return passport.authenticate(cfg.authScheme, cfg.jwtSession);
;
)
【讨论】:
'Authorization' : '<type> <credentials>'
我就这样吗?
它使用jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('JWT'),
我会更新代码。
so request.headers.authorization
会获取 jwt 令牌吗?顺便谢谢你的帮助 :)
立即尝试调用ExtractJwt.fromAuthHeaderWithScheme()
,然后在JWTstrategy
中返回以进行身份验证
好的,让我试试这个。我将提供完整的护照代码,导致我有点困惑。以上是关于反应 axios 401 未经授权的主要内容,如果未能解决你的问题,请参考以下文章
使用 Axios 和 Firebase 时出现 401 未经授权的错误
ReactJS MeteorJS Axios // 401 [未经授权] 错误
在 Laravel 护照、vueJS 和 Axios 中获得未经授权的 401
在Laravel护照,vueJS和Axios中未经授权获得401
如何使用 axios 在 rest-auth 中使用令牌发布? POST http://localhost:8000/rest-auth/password/change/ 401(未经授权)