当前位置:网站首页>Boss: there are too many systems in the company. Can we realize account interworking?
Boss: there are too many systems in the company. Can we realize account interworking?
2022-07-28 10:00:00 【Notes on Shi Shan's architecture】
Source of the article :https://c1n.cn/lGL6r
Catalog
brief introduction
Tradition Session Mechanism and identity authentication scheme
Cluster environment Session Difficulties and solutions
Landing dilemma under multiple services and SSO programme
summary
background
Recently developed new products , Then the boss said that we now have too many systems , It's too troublesome to switch the system login every time , Can we optimize it , Exchange the same account . As a senior architecture lion , The boss's requirements must be met , arrange !

When a company has a rich product matrix , Users switch back and forth between different systems , Of course, the user experience of the product is poor , And increase the cost of user password management .
Nor did it make good use of internal traffic to connect users , And the independent system of each product will lead to the decline of product safety .
Therefore, the realization of single sign on of group products is of great help to the user experience and efficiency improvement . So how to achieve unified authentication ? Let's first learn about traditional authentication methods .
Tradition Session Mechanism and identity authentication scheme
| Cookie Interaction with the server

as everyone knows ,http It's a stateless agreement , So every time customers visit through the browser web.
page , When the request reaches the server , The server will create new threads , Open a new session , And the server doesn't automatically maintain the client's context information .
For example, we now want to implement a shopping cart function in e-commerce , How can we know which shopping cart requests correspond to requests from the same customer ?

So it's happening session The concept ,session Is a mechanism to store context information , It is user oriented , every last SessionID Corresponding to a user , And saved in the server .
session Mainly with cookie or URL Based on rewriting , By default cookie To achieve , The system will create a system called JSESSIONID The variable of is output to cookie in .
JSESSIONID Is stored in the browser memory , It's not written on the hard disk , If we put the browser cookie prohibit , be web The server will use URL Pass by rewriting Sessionid, We can see in the address bar sessionid=KWJHUG6JJM65HS2K6 Strings like that .
Usually JSESSIONID It can't be used across windows , When you open a new browser window and go to the same page , The system will give you a new sessionid, In this way, we can't achieve the goal of information sharing .
| Server side session The mechanism of
When the server receives the request from the client , First, judge whether the request contains JSESSIONID Of sessionId, If it exists, it indicates that it has been created , Directly take it out of memory for use , If you can't find , The description is invalid .
If the customer request does not contain sessionid, Create a session And generate a session The associated sessionid, This sessionid Will be returned to the client in this response to save .
Yes, every time http request , Go through the following steps :
The server first looks for the corresponding cookie Value (sessionid).
according to sessionid, From the server side session Get the correspondence in storage id Of session data , Go back .
If you can't find it sessionid, The server side is created session, Generate sessionid Corresponding cookie, Writes to the response header .
session It's generated by the server , And saved in memory in the form of hash table .
| be based on session Identity authentication process
be based on seesion The main process of identity authentication is as follows :

because http The request is stateless , So in Web field , Most of them are solved in this way . But what's the problem with doing this ? Let's move on .
Cluster environment Session Difficulties and solutions
With the development of technology , User traffic increases , A single server can no longer meet the needs of the system , Distributed architecture is becoming popular .

The system is usually deployed on multiple servers , Distribute the request to one of the servers through load balancing , In this way, it is likely that the requests of the same user will be distributed to different servers .
because session Is saved on the server , So it's very likely that the first request for access A The server , Created session, But a second visit B The server , Then there will be no access to session The situation of .
We know ,Session It is generally used to store the global user information of the session ( It's not just about landing ), For simplification / Accelerate subsequent business requests .
Conventional session Generated and stored on the server side , When an application is deployed in a distributed cluster , How do I guarantee on different servers session Information can be Shared ?
| Session Sharing scheme
Session There are generally two ways to share :
session Copy
session Centralized storage
①session Copy
session Replication will be on different servers session Data replication , The user login , modify , On logout , take session Information is also copied to other machines .

The problem with this implementation is the high implementation cost , High maintenance difficulty , And there will be the problem of delayed registration .
②session Centralized storage

Centralized storage is to get session Stored separately in a service , All access to session Unified to this service .
This avoids synchronizing and maintaining multiple sets session The problem of . We usually use it redis Centralized storage session.
Landing dilemma under multiple services and SSO programme
| SSO The background

If the enterprise becomes bigger , Generally, there are many business support systems to provide corresponding management and IT service , Access multiple systems according to traditional authentication , Each individual system will have its own security system and identity authentication system .
You need to log in to every system , obtain session, Re pass session Access the corresponding system resources .
Such a situation not only brings great difficulties to management , It's also very unfriendly to customers , So how to make customers only need to log in once , You can access multiple systems , You don't need to log in again ?

“ Single sign on ” It is designed to solve such problems . The general thought flow is as follows : Through one ticket Connect user information between systems in series .
| SSO The underlying principle of CAS
①CAS Realize the single sign on process
We know that for systems with completely different domain names ,cookie It cannot be shared across domain names , therefore sessionId It can't be shared on the page , Therefore, it is necessary to realize single store login , You need to enable a domain name specially used for login, such as (ouath.com) To provide... For all systems sessionId.
When the business system is opened , Log in with the help of the central authorization system , The overall process is as follows :
When b.com When open , Find yourself not logged in , So I jump to ouath.com To land
ouath.com The login page is opened , The user enters the account / Password login succeeded
ouath.com Landing successful , Kind of cookie To ouath.com Under domain name
hold sessionid Put it in the background redis, Deposit <ticket,sesssionid> data structure , Then redirect the page to A System
When b.com Reopen , It is found that it is still not logged in , But there's one ticket value
When b.com use ticket value , To redis I found it in the library sessionid, And do session Sync , Then plant cookie Give yourself , Page redirection in place
When b.com Open your own page , Now there is cookie, Background check login status , success
The whole interaction flow chart is as follows :

② Single sign on process demonstration
CAS Login service demo The core code is as follows :
User entity class :
public class UserForm implements Serializable{
private static final long serialVersionUID = 1L;
private String username;
private String password;
private String backurl;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBackurl() {
return backurl;
}
public void setBackurl(String backurl) {
this.backurl = backurl;
}
}Log in to the controller :
@Controller
public class IndexController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/toLogin")
public String toLogin(Model model,HttpServletRequest request) {
Object userInfo = request.getSession().getAttribute(LoginFilter.USER_INFO);
// Not empty , Is logged in
if (null != userInfo){
String ticket = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(ticket,userInfo,2, TimeUnit.SECONDS);
return "redirect:"+request.getParameter("url")+"?ticket="+ticket;
}
UserForm user = new UserForm();
user.setUsername("laowang");
user.setPassword("laowang");
user.setBackurl(request.getParameter("url"));
model.addAttribute("user", user);
return "login";
}
@PostMapping("/login")
public void login(@ModelAttribute UserForm user,HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
System.out.println("backurl:"+user.getBackurl());
request.getSession().setAttribute(LoginFilter.USER_INFO,user);
// Landing successful , Create user information ticket
String ticket = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(ticket,user,20, TimeUnit.SECONDS);
// Redirect , Huiyuan url ---a.com
if (null == user.getBackurl() || user.getBackurl().length()==0){
response.sendRedirect("/index");
} else {
response.sendRedirect(user.getBackurl()+"?ticket="+ticket);
}
}
@GetMapping("/index")
public ModelAndView index(HttpServletRequest request) {
ModelAndView modelAndView = new ModelAndView();
Object user = request.getSession().getAttribute(LoginFilter.USER_INFO);
UserForm userInfo = (UserForm) user;
modelAndView.setViewName("index");
modelAndView.addObject("user", userInfo);
request.getSession().setAttribute("test","123");
return modelAndView;
}
}Login filter :
public class LoginFilter implements Filter {
public static final String USER_INFO = "user";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
Object userInfo = request.getSession().getAttribute(USER_INFO);;
// If you don't log in , Then refuse the request , Turn to the landing page
String requestUrl = request.getServletPath();
if (!"/toLogin".equals(requestUrl)// Not a landing page
&& !requestUrl.startsWith("/login")// Not to log in
&& null == userInfo) {// Not in login status
request.getRequestDispatcher("/toLogin").forward(request,response);
return ;
}
filterChain.doFilter(request,servletResponse);
}
@Override
public void destroy() {
}
}Configure filters :
@Configuration
public class LoginConfig {
// To configure filter take effect
@Bean
public FilterRegistrationBean sessionFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new LoginFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("sessionFilter");
registration.setOrder(1);
return registration;
}
}The login page :
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>enjoy login</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div text-align="center">
<h1> Please login. </h1>
<form action="#" th:action="@{/login}" th:object="${user}" method="post">
<p> user name : <input type="text" th:field="*{username}" /></p>
<p> The secret code : <input type="text" th:field="*{password}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
<input type="text" th:field="*{backurl}" hidden="hidden" />
</form>
</div>
</body>
</html>web System demo The core code is as follows :
filter :
public class SSOFilter implements Filter {
private RedisTemplate redisTemplate;
public static final String USER_INFO = "user";
public SSOFilter(RedisTemplate redisTemplate){
this.redisTemplate = redisTemplate;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
Object userInfo = request.getSession().getAttribute(USER_INFO);;
// If you don't log in , Then refuse the request , Turn to the landing page
String requestUrl = request.getServletPath();
if (!"/toLogin".equals(requestUrl)// Not a landing page
&& !requestUrl.startsWith("/login")// Not to log in
&& null == userInfo) {// Not in login status
String ticket = request.getParameter("ticket");
// There are bills , Then use the ticket to try to get the user information
if (null != ticket){
userInfo = redisTemplate.opsForValue().get(ticket);
}
// Unable to get user information , Then go to the login page
if (null == userInfo){
response.sendRedirect("http://127.0.0.1:8080/toLogin?url="+request.getRequestURL().toString());
return ;
}
/**
* Put user information , Load in session in
*/
UserForm user = (UserForm) userInfo;
request.getSession().setAttribute(SSOFilter.USER_INFO,user);
redisTemplate.delete(ticket);
}
filterChain.doFilter(request,servletResponse);
}
@Override
public void destroy() {
}
}controller :
@Controller
public class IndexController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/index")
public ModelAndView index(HttpServletRequest request) {
ModelAndView modelAndView = new ModelAndView();
Object userInfo = request.getSession().getAttribute(SSOFilter.USER_INFO);
UserForm user = (UserForm) userInfo;
modelAndView.setViewName("index");
modelAndView.addObject("user", user);
request.getSession().setAttribute("test","123");
return modelAndView;
}
}home page :
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>enjoy index</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div th:object="${user}">
<h1>cas-website: Welcome "></h1>
</div>
</body>
</html>③CAS Single sign on and OAuth2 The difference between
OAuth2: Three party authorization agreement , Allow users to..., without providing account and password , Authorize through trusted applications , So that its clients can access resources within their permissions .
CAS: Central certification services (Central Authentication Service), One is based on Kerberos By means of bills SSO Single sign on Framework , by Web Application system provides a reliable single sign on solution ( Belong to Web SSO ).
CAS Ensure the security of user resources on the client during single sign on ;OAuth2 It is to ensure the security of user resources on the server .
CAS The final information to be obtained by the client is , Does this user have access to me (CAS client ) Resources for ;OAuth2 The final information obtained is , I (oauth2 service provider ) Can users' resources make you (oauth2 The client of ) visit .
therefore , Unified account and password are required for identity authentication , use CAS; Third party services need to be authorized to use our resources , Use OAuth2.
Okay , I don't know. You're right SSO Whether there is a deeper understanding , If you have any questions, you can confide in me .
------------- END -------------
Sweep code Free access 600+ page Summary of original boutique articles by Mr. Shi Shan PDF


Summary of original technical articles


You'd better watch it

边栏推荐
- Can multithreading optimize program performance?
- Edge team explains how to improve the comprehensive performance experience through disk cache compression technology
- SkiaSharp 之 WPF 自绘 拖曳小球(案例版)
- pkg打包node工程
- PlatoFarm进展不断,接连上线正式版以及推出超级原始人NFT
- 数据不会说谎,Plato Farm就是元宇宙龙头
- PHP Basics
- OSPF的不规则区域,LSA和序列号
- ConsoleAppender简介说明
- Plato Farm-以柏拉图为目标的农场元宇宙游戏
猜你喜欢

超级原始人系列盲盒即将上线,PlatoFarm赋能超多权益

领域事件和集成事件没那么高大上

Some problems about CLR GC tuning

深度学习必懂的 13 种概率分布

Create SSL certificate using OpenSSL

这款微信插件太好用了

Pulse style | exclusive interview with Committee -- Tencent engineer Zhang Dawei calls you to eat "crab"

Can multithreading optimize program performance?

NET 3行代码实现文字转语音功能

极致通缩和永动机模型,将推动 PlatoFarm 爆发
随机推荐
Net 3 lines of code to realize the function of text to speech
Mock.js
7.27 最小生成树阶段性测试题解
PlatoFarm进展不断,接连上线正式版以及推出超级原始人NFT
PHP Basics
为报复公司解雇,我更改了项目的所有代码注释!
[ESP32][esp-idf] AP+STA实现无线桥接 中转wifi信号
Deepin 下安装 LAMP
How to learn so many conceptual things in database? Seeking method
OSS直连上传-Rails服务实践
j s的数组方法,循环
web之圣杯和双飞翼布局、float、clear、both
3 minutes to tell you how to become a hacker | zero foundation to hacker getting started guide, you only need to master these five abilities
Extreme deflation and perpetual motion machine model will promote the outbreak of platofarm
数据库高级学习笔记--系统包
pycharm使用conda调用远程服务器
Symbolic operation of MATLAB
Translation recommendation | debugging bookkeeper protocol - unbounded ledger
SQL server, MySQL master-slave construction, EF core read-write separation code implementation
Have you ever seen this kind of dynamic programming -- the stock problem of state machine dynamic programming (Part 2)