The editor in this article will introduce in detail how to implement single sign-on based on Node. The content is detailed, the steps are clear, and the details are handled properly. I hope this article on how to implement single sign-on based on Node can help you solve your doubts. Slowly deepen your thinking, let's learn new knowledge together.
With the increase of the company's business, there will inevitably be different systems, if each system needs to log in separately It will be very inconvenient.
Therefore, a solution such as single sign-on came into being. Authorize without logging in again.
For example, Xiao Ming logged in to Taobao today. If he did not log in, he would be asked to enter authentication information (username, password, etc.).
SSO requires an independent authentication center, only an independent authentication center can accept the user's For security information such as user names and passwords, other systems do not provide login entries, and only accept indirect authorization from the authentication center. The whole process can be simply described by the above figure:
When the user logs in to access application A, application A finds that the user is not logged in, jumps to the SSO authentication center, and sends its own address As a parameter, it is convenient to call back
The SSO authentication center finds that the user has not logged in, and guides the user to the login page; the user fills in the user name and password to submit the login application; the SSO authentication center verifies the user information , create a session of the user rain SSO authentication center (the information will be saved in the cookie at this time), and create an authorization token token at the same time
sso authentication center jumps with the token Go to the original request address (application A)
Application A gets the token and goes to the SSO authentication center to verify whether it is valid, and if it returns a valid registration application A
Application A creates a session with the user, displays resources and maintains the user's login status
When the user accesses application B, it is found that the user is not logged in ( The SSO authentication server is not in the same domain as application A and application B, and cannot provide login state), jump to the SSO authentication center, and bring your own address and the cookie information of the previous session with the SSO authentication center
The SSO authentication center finds that the user has logged in, jumps back to the application B address, and attaches the token token
The same application B gets the token Go to the SSO authentication center to verify whether it is valid, if returnedBack to valid registration application B
Application B creates a session with the user, displays resources and maintains the user's login status
Three different services
Here we need to start three services to simulate application A and SSO respectively Authentication server and application B
The service with port number 8383 here is the SSO authentication server, and the rest: 8686 and :8787 represent application A and application B respectively.
In fact, the codes of application A and application B are almost the same. As shown in the figure above, we can set different ports and application names by passing parameters.
Look at the effect first
The first visit jumps to the login page
Application A judges the login status and jumps to the SSO authentication server
Application A
const Koa=require('koa');
const Router=require('koa-router')
const views = require('koa-views')
const static = require('koa-static')
const path = require('path');
const app=new Koa();
const router=new Router();
const session=require('koa-session')
const koa2Req=require('koa2-request');
//template engine related configuration
app.use(views(path.join(__dirname,'./views')),{
extension:'ejs'
})
app.keys=['key']
const keyMap = {
'8686':'koa:sess8686',
'8787':'koa:sess8787'
}
const CONFIG={
key:keyMap[process.env.PORT] || 'koa:sess',
maxAge: 1000*60*60*24,
httpOnly: true
}
app.use(session(CONFIG,app))const system=process.env.SERVER_NAME
router.get("/", async (ctx)=>{
//Judge the login status of application A through session
let user=ctx.session.user
if(user){
//...
}
Else //1. When the user logs in to access application A, application A finds that the user is not logged in (it should be because the server does not save the corresponding session)
{
Let token=ctx.query.token
//There will be no token on the first login url
if(!token)
{
//1. Jump to the SSO authentication server
ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`)
}
else
{
//...
}
}
})
app. use(router. routes())
const port=process.env.PORT||8888
app.listen(port,()=>{
console.log(`app ${system} running at ${port}`)
})
The authentication server judges the login status and renders the login page
Authentication server SSO
The directory structure of the authentication server is as follows It mainly deals with two functions, one is the login logic, and the other is to verify the validity of the token later, which are processed by routing login.js and check-token.js respectively
Auth/ index.js
const Koa=require('koa');
const Router=require('koa-router')
const views = require('koa-views')
const path = require('path');
const app=new Koa();
const router=new Router();
const login=require("./routes/login")
const checkToken=require('./routes/check-token')
const bodyparser = require('koa-bodyparser')
app.use(views(path.join(__dirname,'./views')),{
extension:'ejs'
})
app. use(bodyparser())
//Process login related logic
router. use('/login', login.
routes())
// logic to handle token validation
router.use('/check_token', checkToken.routes())
app. use(router. routes())
app.listen(8383,()=>{
console.log(`app listen at 8383`)
})
Just now we jumped from application A to http://localhost:8383/login?redirectUrl=localhost:8686
to see login Logic in
Auth/routes/login.js
const service = require("../service");
const router=require("koa-router")()
router.get('/', async (ctx) => {
const cookies=ctx.cookies;
const token=cookies. get('token');
//Judging the login status of application A from the cookie
if(token && service.isTokenVailid(token)){
//. . . If you have logged in
}else{
//2. The SSO authentication center finds that the user has not logged in, so the login page is rendered;
await ctx.render('login.ejs',{
extension:'ejs'
})
}
})
//. . .
module.exports=router
login page
Auth/views/login.ejs
Verify user information, create token
Auth/routes/login.js
router.post('/',async (ctx)=>{
//2. The user fills in the user name and password to submit the login application;
const body=ctx.request.body;
const {name,password}=body;
//2. The SSO authentication center verifies the user information,
if(name==="admin" && password==="123456"){
//2. Create a user session with the SSO authentication center (the information will be saved in the cookie at this time), and create an authorization token token at the same time
const token="passport";
await ctx.cookies.set('token',token,{
maxAge: 1000*60*60*24*30,
httpOnly: true
})
If(ctx.query.redirectUrl){
//3. The sso authentication center takes the token and jumps to the original request address (application A)
ctx.redirect(`${ctx.protocol}://${ctx.query.redirectUrl}?token=${token}`)
//The jumpback address is http://localhost:8686/?token=passport
}else{
ctx.body="
Successful login!
"
}
}else{
ctx.response.body={
error: 1,
msg: 'Username or password error'
}
}
})
Jump back to application A with the token from the authentication server
The token verification returns Resource
Application A
app.use(views(path.join(__dirname,'./views')),{
extension:'ejs'
})
//...
const system=process.env.SERVER_NAME
router.get("/", async (ctx)=>{
let user=ctx.session.user
if(user){
//...
}
else
// At this time, application A is still not logged in, but there is a token on the url http://localhost:8686/?token=passport
{
Let token=ctx.query.token
if(!token)
{
//...jump to the SSO login page
}
else
//The logic here goes when jumping back to application A
{
//ajax request 4. Application A gets the token and goes to the SSO authentication center to verify whether it is valid. If it returns a valid registration application A
const url=`://localhost:8383/check_token?token=${token}&t=${new Date().getTime()}`
Let data = await koa2Req(ctx.protocol + url);
`` if(data && data.body){
try {
const body=JSON. parse(data. body)
const {error,userId}=body;
// console.log(error,userId) 0,admin
if(error==0){
If(!userId){
ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`)
return
}
//Register the session after passing the verification, and render the page
//5. Application A creates a session with the user, displays resources and maintains the user's login status
ctx.session.user=userId;
await ctx.render('index.ejs',{
user:userId,
system
})
} else {
ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`)
}
} catch (error) {console.log(error)}
}
}
}
})
app. use(router. routes())
const port=process.env.PORT||8888
app.listen(port,()=>{
console.log(`app ${system} running at ${port}`)
})
The corresponding SSO logic for processing authentication tokens
Auth/routes/check-token
const router=require("koa-router")()
const service=require("../service")
router.get('/', async (ctx) => {
const token=ctx.query.token;
const result={
error: 1
}
//When token is password
if(service.isTokenVailid(token)){
result.error=0;
result.userId='admin'
}
ctx.body=result
the
})
module.exports=router
Auth/service/index.js
module.exports={
isTokenVailid: function(token){
if(token && token==='passport'){
return true
}
return false
}
}
So far, the user has been able to access application A normally, and both the SSO server and the application A server have the information that the user has logged in.
Access application B
Jump to SSO authentication server with cookie
Application B
//...
router.get("/", async (ctx)=>{
let user=ctx.session.user
if(user){
//...
}else{
Let token=ctx.query.token
//...
if(!token)
{
// There is also neither session nor token, jump to the SSO authentication server
//6. When the user accesses application B, it is found that the user has not logged in (the SSO authentication server is not in the same domain as application A and application B, and cannot provide login status), jumps to the SSO authentication center, and compares his address with the previous and The cookie information of the SSO authentication center session is brought in
ctx.redirect(`http://localhost:8383/login?redirectUrl=${ctx.host+ctx.originalUrl}`)
}
else
{
//. . . part of the verification token
}
}
})
app. use(router. routes())
const port=process.env.PORT||8888
app.listen(port,()=>{
console.log(`app ${system} running at ${port}`)
})
Jump back to application B with the token from the authentication server
SSO authentication server, carry it when logging in again cookie, so the login page will not be requested again Auth/routes/login
//...
router.get('/', async (ctx) => {
const cookies=ctx.cookies;
const token=cookies. get('token');
//7. The SSO authentication center finds that the user has logged in, jumps back to the application B address, and attaches the token token
if(token && service.isTokenVailid(token)){
const redirectUrl=ctx.query.redirectUrl;
if(redirectUrl){
//Jump back to application B with the token
ctx.redirect(`${ctx.protocol}://${redirectUrl}?token=${token}`)
}else{
ctx.body="
Successful login!
"
}
}else{
//...render the login page
}
})
//..
Copyright Description:No reproduction without permission。
Knowledge sharing community for developers。
Let more developers benefit from it。
Help developers share knowledge through the Internet。
Follow us