identityserver4是基于.NET Core打造的一款基于 OpenID Connect 和 OAuth 2.0 认证框架,可以很方便的为asp.net core web项目做安全认证等功能, 那这次本文分享如何把identityserver4应用于nodejs的web接口安全。
这里nodejs我们用koa2作为web代码框架来做示范。
1.编写一个hello world的web应用
文件名demo.js,内容如下
const Koa = require('koa');
const Router = require('koa2-router')
const app = new Koa();
const router = new Router();
router.get('/',async (ctx, next) => {
ctx.response.body=`<h1>hello world</h1>`;
});
app.use(router);
app.listen(3000,() => {
console.log(`web app started`);
});
node demo.js启动后,用浏览器测试
2.引入koa-jwt,jwks-rsa相关第三方插件
代码修改如下
const Koa = require('koa');
const Router = require('koa2-router')
const jwt = require('koa-jwt')
const jwksRsa = require('jwks-rsa');
const app = new Koa();
const router = new Router();
const jwksHost = 'http://<identityserver4>'
const issuer = 'http://<issuer>'
app.use(jwt({
secret: jwksRsa.koaJwtSecret({
cache : true,
rateLimit : true,
jwksRequestsPerMinute: 2,
jwksUri: `${jwksHost}/.well-known/openid-configuration/jwks`,
algorithms: [ 'RS256' ]
}),
debug : true,
issuer : issuer
}));
router.get('/',async (ctx, next) => {
ctx.response.body=`<h1>hello world</h1>`;
});
app.use(router);
app.listen(3000,() => {
console.log(`web app started`);
});
代码里面有几个关键参数:
const jwksHost = 'http://<identityserver4>'
const issuer = 'http://<issuer>'
jwksUri: `${jwksHost}/.well-known/openid-configuration/jwks`
<identityserver4>就是你部署identityserver4的主机域名或IP, <issuer>和<jwksUri>这两个值可以直接通过用浏览器访问http://<identityserver4>/.well-known/openid-configuration页面查询下,会返回类似如下页面,请确保代码的值与这个页面的值一致。
修改完代码,启动web: node demo.js, 再次用浏览器访问,出现如下信息
说明安全保护起作用了。
2.使用token测试
为了测试token,我们还是用nodejs脚本模拟客户端,编写一个
test.js文件,内容如下
const { ClientCredentials} = require('simple-oauth2');
const request = require('request')
const config = {
client: {
id: '<client_id>',
secret: '<secret>'
},
auth: {
tokenHost: 'http://<identityserver4>',
tokenPath : "/connect/token"
}
};
const tokenParams = {
};
const authenticate = async function() {
const client = new ClientCredentials(config);
const accessToken = await client.getToken(tokenParams,{json:"force"});
return accessToken.token.access_token;
};
const getWithBearerToken = (url,token,parameters) => new Promise((resolve,reject) => {
request.get( url,
{
qs : parameters,
headers:{ Authorization: `Bearer ${token}` }
}, function (err, resp, body) {
if (err) {
reject(err);
} else if(resp.statusCode != 200)
{
reject(resp.statusMessage);
}
else {
resolve(body);
}
});
});
/** 测试入口 */
(async function(){
const token = await authenticate();
const resp = await getWithBearerToken('http://localhost:3000',token,{});
console.log(resp);
}().catch((err) => {
console.log("exception:" + err);
}));
这里使用Client Credential模式来测试,
id和secret由identityserver4里的配置来提供,代码第一步先验证拿到token,然后再请求上面demo.js的web接口,在请求的header里authorization字段设置为"Bearer <token>",这也是oauth2协议里的标准做法。
然后运行下node test.js, 可以看到控制台输出结果:
进一步,我们可以将demo.js代码里的hello world输出改成如下:
token的信息会被解析到ctx.state.user这个对象里, 然后再用test.js运行测试下,结果类似:
这些输出的信息也就是identityserver4里这个client配置的相关信息。