什么是单点登陆?
单点登录(Single Sign-On,简称 SSO)是一种身份验证和授权机制,在多个应用程序或系统间实现用户一次登录,即可访问多个相关系统,而无需再次输入认证信息。也就是我们所说的一处登陆处处登陆。
web系统由单系统发展成多系统组成的应用群,复杂性应该由系统内部承担,而不是用户。无论web系统内部多么复杂,对用户而言,都是一个统一的整体,也就是说,用户访问web系统的整个应用群与访问单个系统一样,登录/注销只要一次就够了。
单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的,这个限制就是cookie的域(通常对应网站的域名),浏览器发送http请求时会自动携带与该域匹配的cookie,而不是所有cookie。
同域下的单点登录
一个企业一般情况下只有一个域名,通过二级域名区分不同的系统。比如我们有个域名叫做:a.com,同时有两个业务系统分别为:app1.a.com和app2.a.com。我们要做单点登录(SSO),需要一个登录系统,叫做:sso.a.com。
实现方式:
在sso.a.com中登录了,其实是在sso.a.com的服务端的session中记录了登录状态,同时在浏览器端(Browser)的sso.a.com下写入了Cookie。那么我们怎么才能让app1.a.com和app2.a.com登录呢?这里有两个问题:
Cookie是不能跨域的,我们Cookie的domain属性是sso.a.com,在给app1.a.com和app2.a.com发送请求是带不上的。
sso、app1和app2是不同的应用,它们的session存在自己的应用内,是不共享的。
代码实现
全局异常
@ExceptionHandler
public String pException(Exception e){
log.error("异常信息:{}",e);
return "exception";
}
2.在其他未登录的页面实现登陆跳转的操作,一旦登陆,立即返回到原来页面
在web端实现跳转
methods:{
getSkuAll: function(){
$.post("/getSkuAll", {}, function (req){
if("exception"==req){
location.href="http://localhost:8038/login?returnUrl=http://localhost:8040"
}
app.skuList=req;
});
},
methods:{
payPlanAll: function(){
$.post("/payPlanAll", {}, function (req){
if("exception"==req){
location.href="http://localhost:8038/login?returnUrl=http://login:8041"
}
app.planList=req;
});
},
},
进入统一登陆页面
@Autowired
private LoginService loginService;
/**
* 登录页面跳转
* @return
*/
@RequestMapping("/login")
//将cookie储存到response。从login里面取用
public String login(String returnUrl,HttpServletResponse response){
Cookie cookie=new Cookie("returnUrl",returnUrl);
cookie.setDomain("localhost");
cookie.setPath("/");
response.addCookie(cookie);
return "login";
}
/**
*创建一个名为"returnUrl"的Cookie对象,值为传入的返回URL。
*使用setDomain()方法设置Cookie的域为"localhost",这样客户端在访问该域下的其他页面时都会发送该Cookie。
*使用setPath()方法设置Cookie的路径为"/",表示该Cookie在整个网站中都可访问。
*使用response.addCookie()方法将该Cookie添加到HTTP响应中,以便在客户端进行保存。
*返回字符串"login",进入登录页面。
*/
在web端未登录时,会跳转到登陆页面,就是login页面,也是我们所说的统一登录页面,在这里我设置的登陆端口为8038
<head>
<meta charset="UTF-8">
<title>统一登陆平台</title>
</head>
<body>
<div>
<form action="/uums/login" method="post">
<div>
账号:<input name="username" type="text">
</div>
<div>
密码:<input name="password" type="password">
</div>
<div>
<button type="submit">登陆</button>
</div>
</form>
service
根据输入的账号密码进行验证,如果用户名账号密码正确,就会生成一个jwt,然后将jwt放到cookie里面,进入到登陆平台,也就意味登录成功但是如果账号或密码有误,就会重新返回到登录页面,
@Override
public String login(String username, String password) {
String jwt= loginFeign.login(username, password);
if(StringUtils.isEmpty(jwt)
// || !JWTUtil.verify(jwt,"woniu".getBytes())
){
return "login";
}
//把jwt放到cookie
Cookie cookie=new Cookie("token",jwt);
cookie.setDomain("localhost");
cookie.setPath("/");
response.addCookie(cookie);
//验证通过,进入统一登录平台首页
return "index";
}
}
登陆成功之后,首先会进行登陆校验
/**
* 登录验证
* @return
*/
@RequestMapping("/uums/login")
public String uumslogin(String username,String password){
return loginService.login(username,password);
}
验证账号密码是否存在
验证通过之后可以在浏览器查看token
同时其他任何页面,都可以访问,实现单点登陆