SSO 单点登录 的笔记

1  系统中的事务问题

1.1  Spring默认的事务策略

1.1.1    关于代码中的try-catch

说明:

由于代码中采用spring的声明式的事务处理,所有程序员我需关注事务控制,统统交给spring管理.

Spring要求,如果出现了运行时异常,spring才会回滚事务.

如果在代码中对入库操作添加了try-catch ,则spring容器不能接收异常信息,所以不会回滚事务.

 总结:tyr-catch不要加到入库和更新操作上.尽量控制其范围.

2  单点登录

2.1  单点登录介绍

2.1.1    什么是单点登录

说明:用户一次登录后,可以免密登录其相关系统

2.1.2    SSO分析

说明:

当用户登陆QQ游戏时 ,进行了登陆操作,当访问QQ邮箱时,需要再次登录,因为Session没有共享,是不同的对象.所以数据不能公用.

2.1.3    单点登录设计图

2.1.4    单点登录说明:

1.当用户第一次登陆时,先通过SSO单点登录系统进行登录操作.

2.根据用户信息查询用户数据验证登录是否有效

3.如果用户名和密码都正确,则生成ticket.并将User对象转化JSON数据

4.将ticket和UserJSON数据写入redis缓存中

5.当用户登陆成功后,在cookie保存ticket信息.

6.当用户再次访问前台系统时,首先根据ticke信息,查询redis缓存服务器.获取用户数据.

7.当用户访问购物车时,首先前台会校验,根据ticket查询用户信息,如果用户没有登陆则转向单点登录系统.

8.当用户访问订单系统时,首先前台会校验,根据ticket查询用户信息,如果没有该用户信息,则转向单点登录系统.

2.2  构建SSO单点登录服务器

2.2.1    SSO项目说明

单点登录服务器.需要操作数据库,所以构建时需要Controller.Service.Mapper一同完成.

构建web项目.

2.2.2    构建web项目

选择web骨架创建项目

引入jt-parentjar包

引入common

 

2.2.3    导入tomcat插件

<build>

      <plugins>

         <plugin>

            <groupId>org.apache.tomcat.maven</groupId>

            <artifactId>tomcat7-maven-plugin</artifactId>

            <version>2.2</version>

            <configuration>

                <port>8093</port>

                <path>/</path>

            </configuration>

         </plugin>

      </plugins>

   </build>

      

为sso添加启动项

2.2.4    修改Nginx实现转向

说明:通过nginx实现sso.jt.com的转发

#京淘项目单点登录

   server {

      listen80;

      server_namesso.jt.com;

      location/ {

         proxy_passhttp://127.0.0.1:8093;

      }

   }

Nginx修改完成之后 重启nginx

nginx -s reload

2.2.5    修改HOST文件

添加host文件.保证访问sso.jt.com访问本机地址.

2.3  导入配置文件

2.3.1    拷贝jt-manage的配置文件

2.3.2    修改springMVC.xml

2.3.3    修改Spring的配置文件

2.3.4    修改Mybatis配置文件

修改pojo的包路径 和mapper的包路径

 

2.3.5    修改web.xml配置文件

拷贝:manage.jt.com的web.xml配置文件.到jt-sso单点登录中.

<?xml version="1.0"encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns="http://java.sun.com/xml/ns/javaee"

   xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

   id="jt-manage"version="2.5">

   <display-name>jt-sso</display-name>

  

   <!--配置监听器启动spring容器  -->

   <listener>

      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

   </listener>

   <context-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>classpath:/spring/applicationContext*.xml</param-value>

   </context-param>

  

    

   <!--1.配置前端控制器  -->

   <servlet>

      <servlet-name>springmvc</servlet-name>

      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

      <!--配置加载SpringMVC.xml -->

      <init-param>

         <param-name>contextConfigLocation</param-name>

         <param-value>classpath:/spring/springmvc.xml</param-value>

      </init-param>

   </servlet>

   <!--

      / 规定

      1.表示拦截全部的请求 

      2.拦截所有静态资源js/css/image 后期配置放行

       3.放行.jsp资源

   -->

   <servlet-mapping>

      <servlet-name>springmvc</servlet-name>

      <url-pattern>/</url-pattern>

   </servlet-mapping>

  

  

   <!--配置全站乱码解决 POST乱码  -->

   <filter>

      <filter-name>characterEncoding</filter-name>

      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

      <init-param>

         <!--定义默认字符集utf-8  -->

         <param-name>encoding</param-name>

         <param-value>UTF-8</param-value>

      </init-param>

   </filter>

  

   <filter-mapping>

      <filter-name>characterEncoding</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

</web-app>

3  登录业务逻辑

3.1  京淘前台登录跳转

3.1.1    登录/注册的跳转

@Controller

@RequestMapping("/user")

publicclass UserController {

  

   ///user/register.html实现登录和注册页面跳转

   ///user/login.html

   @RequestMapping("/{param}")

   public String module(@PathVariable String param){

     

      //转向用户登陆和注册页面

      returnparam;

   }

}

4  用户注册的校验

4.1  页面JS分析

4.1.1    JS查找

说明:

url:http://sso.jt.com/user/check/admin123/1?r=0.26835501213441115&callback=jsonp1517465570159&_=1517465578846

 

说明:

    页面中通过JSONP的形式直接访问SSO单点登录系统,校验用户名/密码是否存在

4.2  SSO代码编辑

4.2.1    接口文档

请求方法

GET

URL

http://sso.jt.com/user/check/{param}/{type}

参数

格式如:chenchen/1

其中chenchen是校验的数据

Type为类型,可选参数1 username2 phone3 email

示例

http://sso.jt.com/user/check/chenchen/1

返回值

{

status: 200  //200 成功,201 没有查到

msg: “OK”  //返回信息消息

data: false  //返回数据true用户已存在,false用户不存在,可以

}

 

 

4.2.2    编辑POJO对象

@Table(name = "tb_user")

public class User extends BasePojo{

  

   @Id //表示主键信息

   @GeneratedValue(strategy=GenerationType.IDENTITY) //主键自增

   private Long id;   //用户的Id

   private String username; //用户名

   private String password; //密码   采用MD5加密

   private String phone;    //电话

   private String email;    //邮箱

4.2.3    编辑Mapper接口

public interface UserMapper extends SysMapper<User>{

  

   //查询数据是否存在  将数据封装为Map

   int findCheckUser(@Param("param")String param,@Param("cloumn")Stringcloumn);

}

在mybatis文件中编辑userMapper.xml映射文件

<?xml version="1.0"encoding="UTF-8"?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jt.sso.mapper.UserMapper">

  

   <!--使用#号获取数据的值,一般建议使用,因为有预编译的效用.

      $符使用时,只会出现在以列名为参数的应用.

      能用#号不用$

     

      如果在列名的字段中使用#{}取值,相当于

      SELECT COUNT(*) FROM tb_user WHERE "username"= 'admin123'

     -->

   <select id="findCheckUser"resultType="int">

      select count(*) from tb_user where ${cloumn}= #{param}

   </select>

  

  

  

</mapper>

4.2.4    创建service接口和实现类

publicinterface UserService {

   //校验数据是否存在

   Boolean findCheckUser(String param,Integer type);

}

4.2.5    编辑Service实现类

@Service

publicclass UserServiceImpl implementsUserService {

  

   @Autowired

   private UserMapper userMapper;

  

  

   //Type为类型,可选参数1 username2 phone3 email

   //SELECT COUNT(*)FROM tb_user WHERE username= 'admin123'

   @Override

   public Boolean findCheckUser(String param, Integer type) {

     

      String cloumn = null;

      switch (type) {

         case 1: cloumn = "username"; break;

         case 2: cloumn = "phone"; break;

         case 3: cloumn = "email"; break;

      }

      //1,0

      intcount = userMapper.findCheckUser(param,cloumn); 

      returncount ==1 ? true : false;

  

}

4.2.6    编辑Controller

//校验用户的注册信息

   //url:http://sso.jt.com/user/check/admin123/1?callback=jsonp1517465570159&_=1517465578846

   //1 username、2 phone、3 email

   @RequestMapping("/check/{param}/{type}")

   @ResponseBody

   public Object checkUser(@PathVariableString param,@PathVariable Integer type,String callback){

      try {

         //根据传递的参数判断数据是否存在

         Boolean result = userService.findCheckUser(param,type);

         //返回JSONP的数据

         MappingJacksonValue jacksonValue=

                new MappingJacksonValue(SysResult.oK(result));

         jacksonValue.setJsonpFunction(callback);

         returnjacksonValue;

        

      } catch (Exception e) {

         e.printStackTrace();

         returnnull;

     

   }

4.3  用户的注册

4.3.1    JS请求

http://www.jt.com/service/user/doRegister

 

4.4  用户的登陆

4.4.1    登陆的思路

1.当用户点击登陆操作时,跳转到登陆页面

2.用户输入用户名和密码后点击登陆按钮发出请求.进行登录操作.

3.浏览器发出请求:

http://www.jt.com/service/user/doLogin?r=0.582247581950398

4.根据url接收用户名和密码数据

5.再次校验用户名和密码是否为空

6.转向登录页面(js中已将实现)

7.如果用户名和密码都不为null,则调用

8.UserService 通过httpClient方式发送数据

9.如果获取的ticket不为null.则表示登录操作成功.如果ticket为null,直接返回null.

将ticket信息写入到Cookie中

4.5  实现前台的登陆操作

4.5.1    页面分析JS

JS:http://www.jt.com/service/user/doLogin?r=0.582247581950398

 

4.5.2    编辑UserController

//用户登陆 http://www.jt.com/service/user/doLogin?r=0.582247581950398

   //通过login.jsp检测登陆的username和password是否正确

   @RequestMapping("/doLogin")

   @ResponseBody

   public SysResult doLogin(String username,String password,

         HttpServletRequest request,HttpServletResponseresponse){

      //判断用户名和密码是否为null

      if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){

         return SysResult.build(201, "用户名密码不能为空");

      }

      //当前输入的用户名是正确的

      try {

         //获取用户的ticket

         String ticket =

                userService.findUserByUP(username,password);

         //ticket不为空

         if(!StringUtils.isEmpty(ticket)){

            //如果ticket数据不为空 则写入cookie

            //Cookie[] cookies = request.getCookies();

            //Cookie的名称必须为 JT_TICKET

         CookieUtils.setCookie(request, response, "JT_TICKET", ticket);

            return SysResult.oK(ticket);

         }

      } catch (Exception e) {

         e.printStackTrace();

      }

     

      return SysResult.build(201, "用户登陆失败");

   }

4.5.3    编辑UserService

@Override

   public String findUserByUP(String username, String password) {

      String uri = "http://sso.jt.com/user/login";

      Map<String, String> map = new HashMap<String,String>();

      //注意不要有空格

      map.put("username", username);

      map.put("password", password);

      try {

         String resutJSON = httpClient.doPost(uri,map);

        

         //判断数据是否有效  将其转化为Sysresult对象

         SysResult sysResult =

         objectMapper.readValue(resutJSON,SysResult.class);

         //判断SSO返回是否正确

         if(sysResult.getStatus() == 200){

            return (String) sysResult.getData();

         }

        

      } catch (Exception e) {

         e.printStackTrace();

      }

      returnnull;

   }

5  作业:

1.  试着完成用户登陆操作.

2.  试写用户登陆回显操作

说明:当用户登陆成功后,页面会发出请求.根据ticket从redis中查询用户信息

请求路径:http://sso.jt.com/user/query/ticket信息

    根据业务接口文件,查询用户信息.

最终实现效用:

猜你喜欢

转载自blog.csdn.net/qq_40680190/article/details/79764935