2023年8月1日发(作者:)
什么是单点登陆系统(SSO)?什么是单点登录系统单点登录的英⽂名叫做:Single Sign On(简称SSO)。在初学/以前的时候,⼀般我们就单系统,所有的功能都在同⼀个系统上。后来,我们为了合理利⽤资源和降低耦合性,于是把单系统拆分成多个⼦系统。⽐如阿⾥系的淘宝和天猫,很明显地我们可以知道这是两个系统,但是你在使⽤的时候,登录了天猫,淘宝也会⾃动登录。简单来说,单点登录就是在多个系统中,⽤户只需⼀次登录,各个系统即可感知该⽤户已经登录。单点登录系统特点分析HTTP协议是⽆状态的,Session不能依据HTTP连接来判断是否为同⼀个⽤户。于是乎:服务器向⽤户浏览器发送了⼀个名为JESSIONID的Cookie,它的值是Session的id值。其实Session是依据Cookie来识别是否是同⼀个⽤户。⼀般我们单系统实现登录会这样做:1、 登录:将⽤户信息保存在Session对象中如果在Session对象中能查到,说明已经登录如果在Session对象中查不到,说明没登录(或者已经退出了登录)2、注销(退出登录):从Session中删除⽤户的信息记住我(关闭掉浏览器后,重新打开浏览器还能保持登录状态):配合Cookie来⽤。多系统登录的问题与解决⼀ Session不共享问题解决系统之间Session不共享问题有⼀下⼏种⽅案:1、 Tomcat集群Session全局复制(集群内每个tomcat的session完全同步)【会影响集群的性能呢,不建议】2、根据请求的IP进⾏Hash映射到对应的机器上(这就相当于请求的IP⼀直会访问同⼀个服务器)【如果服务器宕机了,会丢失了⼀⼤部分Session的数据,不建议】3、把Session数据放在Redis中(使⽤Redis模拟Session)【建议】SSO系统⽣成⼀个token,并将⽤户信息存到Redis中,并设置过期时间其他系统请求SSO系统进⾏登录,得到SSO返回的token,写到Cookie中每次请求时,Cookie都会带上,拦截器得到token,判断是否已经登录到这⾥,其实我们会发现其实就两个变化:将登陆功能抽取为⼀个系统(SSO),其他系统请求SSO进⾏登录本来将⽤户信息存到Session,现在将⽤户信息存到Redis。1、服务端将Cookie写到客户端后,客户端对Cookie进⾏解析,将Token解析出来,此后请求都把这个Token带上就⾏了多个域名共享Cookie,2、在写到客户端的时候设置Cookie的domain。3、将Token保存在SessionStroage中(不依赖Cookie就没有跨域的问题了)三CAS原理(认证中⼼)CAS (Central Authentication Service),下⾯说说CAS是怎么搞的。⼀个独⽴的认证中⼼,只有认证中⼼能接受⽤户的⽤户名密码等安全信息,其他系统不提供登录⼊⼝,只接受认证中⼼的间接授权。间接授权通过令牌实现,sso认证中⼼验证⽤户的⽤户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个⼦系统,⼦系统拿到令牌,即得到了授权,可以借此创建会话,例如##具体实现第⼀步:创建项⽬聚合⼯程创建聚合⼯程的⽬的是对项⽬中的资源(例如⼀些依赖)进⾏统⼀管理,多个项⽬module之间共享资源.这次项⽬的maven⼯程结构如下:|—04-jt-sso|–sso-auth #认证服务器|–sso-resource #资源服务器|– #公共依赖及版本管理第⼆步:创建⼏个单独的系统。1、两个⼯具类第⼀步:定义JWT⼯具类,⽤于创建,解析,验证token,代码如下:package ;public class JwtUtils {private static String secret=“AAABBBCCCDDDEEE”;/*基于负载和算法创建token信息/public static String generatorToken(Map map){return r()return r().setClaims(map).setExpiration(new Date(tTimeMillis()+30601000)).setIssuedAt(new Date()).signWith(256,secret).compact();//签约,创建token}/*解析token获取数据/public static Claims getClaimsFromToken(String token){return ().setSigningKey(secret).parseClaimsJws(token).getBody();}/*判定token是否失效/public static boolean isTokenExpired(String token){Date expiration=getClaimsFromToken(token).getExpiration();return (new Date());}}第⼆步:定义Web⼯具类,⽤于向客户端响应json数据package ;public class WebUtils {public static void writeJsonToClient(HttpServletResponse response, Map map)throws IOException {//1设置响应数据的编码racterEncoding(“utf-8”);//2告诉浏览器响应数据的内容类型以及编码tentType(“application/json;charset=utf-8”);//3获取输出流对象PrintWriter out=ter();//4 将map转换为json数据String result=new ObjectMapper().writeValueAsString(map);//5 将数据响应到客户端n(result);();}}安全配置类:package ;@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic BCryptPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {//1.关闭跨域攻击().disable();//2.配置登录url(登录表单使⽤哪个页⾯)gin().successHandler(authenticationSuccessHandler()).failureHandler(authenticationFailureHandler());//设置需要认证与拒绝访问的异常处理器ionHandling().authenticationEntryPoint(authenticationEntryPoint());//3.放⾏登录url(不需要认证就可以访问)izeRequests()izeRequests().anyRequest().authenticated();//除了以上资源必须认证才可访问}//认证成功处理器public AuthenticationSuccessHandler authenticationSuccessHandler(){return (httpServletRequest, httpServletResponse,authentication)-> {User principal = (User)ncipal();Map map=new HashMap<>();(“state”,200);(“message”,“Login ok”);Map jwtMap=new HashMap<>();(“username”, rname());List authorities = new ArrayList<>();horities().forEach((authority)-> {(hority());});(“authorities”,authorities);String token=torToken(jwtMap);(“token”, token);sonToClient(httpServletResponse,map);};}//认证失败处理器public AuthenticationFailureHandler authenticationFailureHandler(){return (httpServletRequest, httpServletResponse, e) -> {Map map=new HashMap<>();(“state”,500);(“msg”,“username or password error”);sonToClient(httpServletResponse,map);};}//没有认证时执⾏DefaultAuthenticationEntryPoint对象public AuthenticationEntryPoint authenticationEntryPoint(){return (httpServletRequest, httpServletResponse, e)->{Map map=new HashMap<>();(“state”,401);//SC_UNAUTHORIZED 的值为(“message”,“请先登录再访问”);sonToClient(httpServletResponse,map);};}}认证逻辑对象
2023年8月1日发(作者:)
什么是单点登陆系统(SSO)?什么是单点登录系统单点登录的英⽂名叫做:Single Sign On(简称SSO)。在初学/以前的时候,⼀般我们就单系统,所有的功能都在同⼀个系统上。后来,我们为了合理利⽤资源和降低耦合性,于是把单系统拆分成多个⼦系统。⽐如阿⾥系的淘宝和天猫,很明显地我们可以知道这是两个系统,但是你在使⽤的时候,登录了天猫,淘宝也会⾃动登录。简单来说,单点登录就是在多个系统中,⽤户只需⼀次登录,各个系统即可感知该⽤户已经登录。单点登录系统特点分析HTTP协议是⽆状态的,Session不能依据HTTP连接来判断是否为同⼀个⽤户。于是乎:服务器向⽤户浏览器发送了⼀个名为JESSIONID的Cookie,它的值是Session的id值。其实Session是依据Cookie来识别是否是同⼀个⽤户。⼀般我们单系统实现登录会这样做:1、 登录:将⽤户信息保存在Session对象中如果在Session对象中能查到,说明已经登录如果在Session对象中查不到,说明没登录(或者已经退出了登录)2、注销(退出登录):从Session中删除⽤户的信息记住我(关闭掉浏览器后,重新打开浏览器还能保持登录状态):配合Cookie来⽤。多系统登录的问题与解决⼀ Session不共享问题解决系统之间Session不共享问题有⼀下⼏种⽅案:1、 Tomcat集群Session全局复制(集群内每个tomcat的session完全同步)【会影响集群的性能呢,不建议】2、根据请求的IP进⾏Hash映射到对应的机器上(这就相当于请求的IP⼀直会访问同⼀个服务器)【如果服务器宕机了,会丢失了⼀⼤部分Session的数据,不建议】3、把Session数据放在Redis中(使⽤Redis模拟Session)【建议】SSO系统⽣成⼀个token,并将⽤户信息存到Redis中,并设置过期时间其他系统请求SSO系统进⾏登录,得到SSO返回的token,写到Cookie中每次请求时,Cookie都会带上,拦截器得到token,判断是否已经登录到这⾥,其实我们会发现其实就两个变化:将登陆功能抽取为⼀个系统(SSO),其他系统请求SSO进⾏登录本来将⽤户信息存到Session,现在将⽤户信息存到Redis。1、服务端将Cookie写到客户端后,客户端对Cookie进⾏解析,将Token解析出来,此后请求都把这个Token带上就⾏了多个域名共享Cookie,2、在写到客户端的时候设置Cookie的domain。3、将Token保存在SessionStroage中(不依赖Cookie就没有跨域的问题了)三CAS原理(认证中⼼)CAS (Central Authentication Service),下⾯说说CAS是怎么搞的。⼀个独⽴的认证中⼼,只有认证中⼼能接受⽤户的⽤户名密码等安全信息,其他系统不提供登录⼊⼝,只接受认证中⼼的间接授权。间接授权通过令牌实现,sso认证中⼼验证⽤户的⽤户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个⼦系统,⼦系统拿到令牌,即得到了授权,可以借此创建会话,例如##具体实现第⼀步:创建项⽬聚合⼯程创建聚合⼯程的⽬的是对项⽬中的资源(例如⼀些依赖)进⾏统⼀管理,多个项⽬module之间共享资源.这次项⽬的maven⼯程结构如下:|—04-jt-sso|–sso-auth #认证服务器|–sso-resource #资源服务器|– #公共依赖及版本管理第⼆步:创建⼏个单独的系统。1、两个⼯具类第⼀步:定义JWT⼯具类,⽤于创建,解析,验证token,代码如下:package ;public class JwtUtils {private static String secret=“AAABBBCCCDDDEEE”;/*基于负载和算法创建token信息/public static String generatorToken(Map map){return r()return r().setClaims(map).setExpiration(new Date(tTimeMillis()+30601000)).setIssuedAt(new Date()).signWith(256,secret).compact();//签约,创建token}/*解析token获取数据/public static Claims getClaimsFromToken(String token){return ().setSigningKey(secret).parseClaimsJws(token).getBody();}/*判定token是否失效/public static boolean isTokenExpired(String token){Date expiration=getClaimsFromToken(token).getExpiration();return (new Date());}}第⼆步:定义Web⼯具类,⽤于向客户端响应json数据package ;public class WebUtils {public static void writeJsonToClient(HttpServletResponse response, Map map)throws IOException {//1设置响应数据的编码racterEncoding(“utf-8”);//2告诉浏览器响应数据的内容类型以及编码tentType(“application/json;charset=utf-8”);//3获取输出流对象PrintWriter out=ter();//4 将map转换为json数据String result=new ObjectMapper().writeValueAsString(map);//5 将数据响应到客户端n(result);();}}安全配置类:package ;@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic BCryptPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {//1.关闭跨域攻击().disable();//2.配置登录url(登录表单使⽤哪个页⾯)gin().successHandler(authenticationSuccessHandler()).failureHandler(authenticationFailureHandler());//设置需要认证与拒绝访问的异常处理器ionHandling().authenticationEntryPoint(authenticationEntryPoint());//3.放⾏登录url(不需要认证就可以访问)izeRequests()izeRequests().anyRequest().authenticated();//除了以上资源必须认证才可访问}//认证成功处理器public AuthenticationSuccessHandler authenticationSuccessHandler(){return (httpServletRequest, httpServletResponse,authentication)-> {User principal = (User)ncipal();Map map=new HashMap<>();(“state”,200);(“message”,“Login ok”);Map jwtMap=new HashMap<>();(“username”, rname());List authorities = new ArrayList<>();horities().forEach((authority)-> {(hority());});(“authorities”,authorities);String token=torToken(jwtMap);(“token”, token);sonToClient(httpServletResponse,map);};}//认证失败处理器public AuthenticationFailureHandler authenticationFailureHandler(){return (httpServletRequest, httpServletResponse, e) -> {Map map=new HashMap<>();(“state”,500);(“msg”,“username or password error”);sonToClient(httpServletResponse,map);};}//没有认证时执⾏DefaultAuthenticationEntryPoint对象public AuthenticationEntryPoint authenticationEntryPoint(){return (httpServletRequest, httpServletResponse, e)->{Map map=new HashMap<>();(“state”,401);//SC_UNAUTHORIZED 的值为(“message”,“请先登录再访问”);sonToClient(httpServletResponse,map);};}}认证逻辑对象
发布评论