<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          redis實現(xiàn)單點登錄系統(tǒng)

          共 44441字,需瀏覽 89分鐘

           ·

          2021-06-03 02:18


          單點登錄介紹 
          SSO英文全稱Single Sign On,單點登錄。SSO是在多個應用系統(tǒng)中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統(tǒng)。它包括可以將這次主要的登錄映射到其他應用中用于同一個用戶的登錄的機制。它是目前比較流行的企業(yè)業(yè)務整合的解決方案之一。

          為什么要單點登錄

          在平常寫案例的時候,如果只有一個web工程。如果要訪問用戶相關信息,那么我們通常會寫個攔截器,從session中看能不能取到用戶信息,如果不能那么需要返回到登錄頁面,用戶登錄后將用戶信息保存到session中,那么在此訪問用戶中心就沒問題了。然后這種做法在一個web工程中是沒問題的。 

          如果系統(tǒng)是分布式的情況呢,比如拿商城來說,它是一個分布式的,什么會員模塊,商品管理模塊,購物車模塊,訂單模塊等。如果還用上面那張驗證方式的話,訪問a模塊的話發(fā)現(xiàn)沒登錄,然后跳轉頁面登錄了,信息存入session中,如果下次訪問的是b模塊,由于模塊都是存在于不同的服務器session中肯定沒有登錄用戶信息,那么肯定是訪問不通過要求重新登錄。而且,為了解決高并發(fā)還得進行集群,即使是兩次訪問同一模塊,也有可能訪問的是集群中的另外一臺服務器,這樣就存在多次要求登錄的問題。 

          解決:我們可以整個Session服務器(SSO系統(tǒng))專門用來處理登錄問題,這樣用戶每次訪問用戶中心的時候都來該服務器判斷用戶有沒有登錄,如果登錄了放行,沒有登錄就跳轉到登錄頁面,登錄后將用戶信息保存到Session服務器中,我們需要用redis來模擬從前的session,以前用戶信息存入redis中,這里我們就將用戶信息存入redis中。

          那么怎么存,用什么做key什么做value呢?在一個web工程的時候,用戶信息存入session是這樣設置的session.setArrtribute(“admin”,user),獲取則是session.getAttribute(“admin”);

          很自然的想到用用戶id做為key,但是不要這樣做,因為這樣是不能區(qū)分不同的連接的,比如你在A電腦登錄了tom這個賬號,信息存入redis中了且key為tom的id。然后換個電腦B,但是不直接登錄卻直接訪問用戶中心(比如訂單結算),那么能不能訪問呢?是可以訪問的,因為redis中存了這么個鍵值對啊,然后就能取出來用戶信息說明已經(jīng)登錄了,所以肯定給訪問。但是這樣是不合理的,不應該換電腦登錄還能直接訪問用戶中心。 
          用一個web工程使用tomcat服務器的時候,tomcat是怎么區(qū)分不同連接的呢,實際上每次獲取session的時候tomcat會生成一個JSESSIONID的作為標識,然后返回給瀏覽器存到Cookie里面,下次再訪問的時候會帶著這個JSESSIONID來訪問,然后tomcat拿到這個標識會去尋找對應的session,再從中取出用戶信息,這樣如果換電腦B了,B瀏覽器里面是沒有這個JSESSIONID的,那么在服務端也找不到對應的session更別說取到用戶信息了,所以要求重新登錄。 
          既然是打算用redis來模擬session,那么也可以這樣做。用戶每次登錄的時候都會生成一個唯一的表示token,用它來作為key,用戶信息作為value,然后將token存到Cookie里面返給瀏覽器。用戶下次 
          訪問用戶中心的時候,從Cookie里面取token,再用token從redis中取用戶信息,來判斷是否允許訪問用戶中心。 
          這樣做,只要用戶換電腦登錄了,那么Cookie里面就沒有這個token就查不到用戶信息所以必須要重新登錄了,分析到這基本上也能做了。 

          前期準備好的jar包 
          e3-common(jar)里面存放的是一些工具類 
          e3-manager-pojo(jar)里面存放的是mybatis逆向工程生成的Mapper和映射文件。 
          1、SSO工程搭建 
          e3-sso(pom) 
          |–e3-sso-interface(jar) 
          |–e3-sso-service(war) 
          e3-sso-web(war)

          e3-sso需要引入的jar包 
          pom.xml中

          <groupId>cn.e3mall</groupId>
            <artifactId>e3-sso</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <packaging>pom</packaging>
            <modules>
              <module>e3-sso-interface</module>
              <module>e3-sso-service</module>
            </modules>
            <dependencies>
              <dependency>
                  <groupId>cn.e3mall</groupId>
                <artifactId>e3-common</artifactId>
                <version>0.0.1-SNAPSHOT</version>
              </dependency>
            </dependencies>
            <!-- 配置tomcat插件 -->
            <build>
              <plugins>
                  <plugin>
                      <!-- 配置Tomcat插件 -->
                      <groupId>org.apache.tomcat.maven</groupId>
                      <artifactId>tomcat7-maven-plugin</artifactId>
                      <configuration>
                          <path>/</path><!-- 表示訪問時候不帶工程名的 -->
                          <port>8087</port>
                      </configuration>
                  </plugin>
              </plugins>
            </build>

          e3-sso-interface引入jar包 
          pom.xml中

          <parent>
              <groupId>cn.e3mall</groupId>
              <artifactId>e3-sso</artifactId>
              <version>0.0.1-SNAPSHOT</version>
            </parent>
            <artifactId>e3-sso-interface</artifactId>
            <dependencies>
              <dependency>
                  <groupId>cn.e3mall</groupId>
              <artifactId>e3-manager-pojo</artifactId>
              <version>0.0.1-SNAPSHOT</version>
              </dependency>
            </dependencies>

          e3-sso-service引入jar包 
          pom.xml中

          <parent>
              <groupId>cn.e3mall</groupId>
              <artifactId>e3-sso</artifactId>
              <version>0.0.1-SNAPSHOT</version>
            </parent>
            <artifactId>e3-sso-service</artifactId>
            <packaging>war</packaging>
            <dependencies>
              <dependency>
                  <groupId>cn.e3mall</groupId>
                  <artifactId>e3-manager-dao</artifactId>
                  <version>0.0.1-SNAPSHOT</version>
              </dependency>
              <dependency>
                  <groupId>cn.e3mall</groupId>
              <artifactId>e3-sso-interface</artifactId>
              <version>0.0.1-SNAPSHOT</version>
              </dependency>
              <!-- Spring -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-beans</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-jdbc</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-aspects</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-jms</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context-support</artifactId>
              </dependency>
              <!-- dubbo相關 -->
                  <dependency>
                      <groupId>com.alibaba</groupId>
                      <artifactId>dubbo</artifactId>
                      <exclusions>
                          <exclusion>
                              <groupId>org.springframework</groupId>
                              <artifactId>spring</artifactId>
                          </exclusion>
                          <exclusion>
                              <groupId>org.jboss.netty</groupId>
                              <artifactId>netty</artifactId>
                          </exclusion>
                      </exclusions>
                  </dependency>
                  <dependency>
                      <groupId>org.apache.zookeeper</groupId>
                      <artifactId>zookeeper</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>com.github.sgroschupf</groupId>
                      <artifactId>zkclient</artifactId>
                  </dependency>
            </dependencies>

          spring配置文件1中:配置數(shù)據(jù)源以及spring與mybatis整合

          <!-- 數(shù)據(jù)庫連接池 -->
              <!-- 加載配置文件 -->
              <context:property-placeholder location="classpath:conf/*.properties" />
              <!-- 數(shù)據(jù)庫連接池 -->
              <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
                  destroy-method="close">
                  <property name="url" value="${jdbc.url}" />
                  <property name="username" value="${jdbc.username}" />
                  <property name="password" value="${jdbc.password}" />
                  <property name="driverClassName" value="${jdbc.driver}" />
                  <property name="maxActive" value="10" />
                  <property name="minIdle" value="5" />
              </bean>
              <!-- 讓spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
              <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
                  <!-- 數(shù)據(jù)庫連接池 -->
                  <property name="dataSource" ref="dataSource" />
                  <!-- 加載mybatis的全局配置文件 -->
                  <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
              </bean>
              <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                  <property name="basePackage" value="cn.e3mall.mapper" />
              </bean>

          spring配置文件2中:配置事務

          <!-- 事務管理器 -->
              <bean id="transactionManager"
                  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                  <!-- 數(shù)據(jù)源 -->
                  <property name="dataSource" ref="dataSource" />
              </bean>
              <!-- 通知 -->
              <tx:advice id="txAdvice" transaction-manager="transactionManager">
                  <tx:attributes>
                      <!-- 傳播行為 -->
                      <tx:method name="save*" propagation="REQUIRED" />
                      <tx:method name="insert*" propagation="REQUIRED" />
                      <tx:method name="add*" propagation="REQUIRED" />
                      <tx:method name="create*" propagation="REQUIRED" />
                      <tx:method name="delete*" propagation="REQUIRED" />
                      <tx:method name="update*" propagation="REQUIRED" />
                      <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
                      <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
                      <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
                  </tx:attributes>
              </tx:advice>
              <!-- 切面 -->
              <aop:config>
                  <aop:advisor advice-ref="txAdvice"
                      pointcut="execution(* cn.e3mall.sso.service..*.*(..))" />
              </aop:config>

          spring配置文件3中配置redis

          <!-- 連接redis單機版 -->
              <bean id="jedisClientPool" class="cn.e3mall.common.jedis.JedisClientPool">
                  <property name="jedisPool" ref="jedisPool"></property>
              </bean>
              <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
              <!-- 一定要用name,構造方法太多用index容易錯 -->
                  <constructor-arg name="host" value="192.168.25.128"/>
                  <constructor-arg name="port" value="6379"/>
              </bean>

          spring配置文件中配置:發(fā)布服務,組件掃描,寫完服務再給出

          web.xml中

          <!-- 加載spring容器 -->
              <context-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:spring/applicationContext*.xml</param-value>
              </context-param>
              <listener>
                  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
              </listener>

          配置文件db.properties中配置數(shù)據(jù)庫連接

          jdbc.driver=com.mysql.jdbc.Driver
          jdbc.url=jdbc:mysql://localhost:3306/e3mall_32?characterEncoding=utf-8
          jdbc.username=root
          jdbc.password=123456

          resource.properties中設置token過期時間

          SESSION_EXPIRE=1800

          e3-sso-web引入jar包 
          pom.xml中

          <groupId>cn.e3mall</groupId>
            <artifactId>e3-sso-web</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <packaging>war</packaging>
            <dependencies>
              <dependency>
                <groupId>cn.e3mall</groupId>
                  <artifactId>e3-sso-interface</artifactId>
                  <version>0.0.1-SNAPSHOT</version>   
              </dependency>
              <!-- JSP相關 -->
              <dependency>
                  <groupId>jstl</groupId>
                  <artifactId>jstl</artifactId>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>jsp-api</artifactId>
                  <scope>provided</scope>
              </dependency>
              <!-- Spring -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-beans</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-jdbc</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-aspects</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-jms</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context-support</artifactId>
              </dependency>
              <!-- dubbo相關 -->
                  <dependency>
                      <groupId>com.alibaba</groupId>
                      <artifactId>dubbo</artifactId>
                      <exclusions>
                          <exclusion>
                              <groupId>org.springframework</groupId>
                              <artifactId>spring</artifactId>
                          </exclusion>
                          <exclusion>
                              <groupId>org.jboss.netty</groupId>
                              <artifactId>netty</artifactId>
                          </exclusion>
                      </exclusions>
                  </dependency>
                  <dependency>
                      <groupId>org.apache.zookeeper</groupId>
                      <artifactId>zookeeper</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>com.github.sgroschupf</groupId>
                      <artifactId>zkclient</artifactId>
                  </dependency>

            </dependencies>
            <!-- 配置tomcat插件 -->
            <build>
              <plugins>
                  <plugin>
                      <!-- 配置Tomcat插件 -->
                      <groupId>org.apache.tomcat.maven</groupId>
                      <artifactId>tomcat7-maven-plugin</artifactId>
                      <configuration>
                          <path>/</path><!-- 表示訪問時候不帶工程名的 -->
                          <port>8088</port>
                      </configuration>
                  </plugin>
              </plugins>
            </build>

          spring配置文件中除了組件掃描之外還要引用服務,但是Service層還沒發(fā)布服務,所以待會給出,另外還需要將jsp頁面跟靜態(tài)文件都引入到項目的WEB-INF和webaap下。

          web.xml中

          <!-- 解決post亂碼 -->
              <filter>
                  <filter-name>CharacterEncodingFilter</filter-name>
                  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                  <init-param>
                      <param-name>encoding</param-name>
                      <param-value>utf-8</param-value>
                  </init-param>
              </filter>
              <filter-mapping>
                  <filter-name>CharacterEncodingFilter</filter-name>
                  <url-pattern>/*</url-pattern>
              </filter-mapping>


              <!-- springmvc的前端控制器 -->
              <servlet>
                  <servlet-name>e3-manager</servlet-name>
                  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                  <!-- contextConfigLocation不是必須的, 如果不配置contextConfigLocation, springmvc的配置文件默認在:WEB-INF/servlet的name+"-servlet.xml" -->
                  <init-param>
                      <param-name>contextConfigLocation</param-name>
                      <param-value>classpath:spring/springmvc.xml</param-value>
                  </init-param>
                  <load-on-startup>1</load-on-startup>
              </servlet>
              <servlet-mapping>
                  <servlet-name>e3-manager</servlet-name>
                  <!-- 偽靜態(tài)化,搜索引擎優(yōu)化,搜索引擎會先找靜態(tài)頁面 -->
                  <url-pattern>/</url-pattern>
              </servlet-mapping>

          屬性配置文件resource.properties中

          TOKEN_KEY=token

          功能實現(xiàn) 
          服務層:e3-sso-service中

          1. 接收參數(shù),判斷用戶名和密碼正確

          2. 用戶名和密碼都正確的話,生成token,相當于tomcat時候的jsessionId.用uuid生成,保證唯一性。

          3. 將用戶信息存入redis。Key為”SESSION”+token,value為查詢的用戶信息轉為的json串。

          4. 設置key的有效期。一般為半個小時

          5. 返回包裝了token的E3Result

          /*
           * 用戶登錄處理
           */
          @Service
          public class LoginServiceImpl implements LoginService{

              @Autowired
              private TbUserMapper userMapper;
              @Autowired
              private JedisClient jedisClient;
              @Value("${SESSION_EXPIRE}")
              private Integer SESSION_EXPIRE;
              public E3Result userLogin(String username, String password) {

                  //1.判斷用戶名和密碼是否正確
                  //根據(jù)用戶名查詢用戶信息
                  TbUserExample example = new TbUserExample();
                  Criteria criteria = example.createCriteria();
                  criteria.andUsernameEqualTo(username);
                  List<TbUser> list = userMapper.selectByExample(example);
                  if(list == null || list.size() == 0){
                      //返回登錄失敗
                      return E3Result.build(400, "用戶名或者密碼錯誤");
                  }
                  //取用戶信息
                  TbUser user = list.get(0);
                  //判斷密碼是否正確
                  if(!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())){
                      //2.如果不正確返回登錄失敗
                      return E3Result.build(400, "用戶名或者密碼錯誤");
                  }
                  //3.如果正確生成token
                  String token = UUID.randomUUID().toString();//生成的uuid必不重復
                  //4.把用戶信息寫入redis,key:token,value:用戶信息
                  user.setPassword(null);
                  jedisClient.set("SESSION:"+ token, JsonUtils.objectToJson(user));
                  //5.設置Session的過期時間
                  jedisClient.expire("SESSION:"+ token, SESSION_EXPIRE);
                  //6.把token返回
                  return E3Result.ok(token);
              }
          }

          注:如果沒用過mybatis逆向工程那么花2小時學一下這樣看上面的代碼更清晰。

          E3Result為自定義響應類,如下

          public class E3Result implements Serializable{

              // 定義jackson對象
              private static final ObjectMapper MAPPER = new ObjectMapper();
              // 響應業(yè)務狀態(tài)
              private Integer status;
              // 響應消息
              private String msg;
              // 響應中的數(shù)據(jù)
              private Object data;
              public static E3Result build(Integer status, String msg, Object data) {
                  return new E3Result(status, msg, data);
              }
              public static E3Result ok(Object data) {
                  return new E3Result(data);
              }
              public static E3Result ok() {
                  return new E3Result(null);
              }
              public E3Result() {
              }
              public static E3Result build(Integer status, String msg) {
                  return new E3Result(status, msg, null);
              }
              public E3Result(Integer status, String msg, Object data) {
                  this.status = status;
                  this.msg = msg;
                  this.data = data;
              }
              public E3Result(Object data) {
                  this.status = 200;
                  this.msg = "OK";
                  this.data = data;
              }
              get、set方法
             }

          服務寫完之后需要發(fā)布服務(使用了Dubbo發(fā)布服務,Zookeeper作為注冊中心) 
          配置文件4中:組件掃描,發(fā)布服務

          <context:component-scan base-package="cn.e3mall.sso.service"/>

              <!-- 使用dubbo發(fā)布服務 -->
              <!-- 提供方應用信息,用于計算依賴關系 -->
              <dubbo:application name="e3-sso" />
              <dubbo:registry protocol="zookeeper"
                  address="192.168.25.128:2181" />
              <!-- 用dubbo協(xié)議在20880端口暴露服務 -->
              <dubbo:protocol name="dubbo" port="20883" /><!-- 一個服務對應一個端口 -->
              <!-- 聲明需要暴露的服務接口 -->
              <dubbo:service interface="cn.e3mall.sso.service.LoginService" 
                  ref="loginServiceImpl" timeout="600000"/>
              <dubbo:service>

          然后將e3-sso工程安裝到本地倉庫

          表現(xiàn)層:e3-sso-web中 
          先要接收服務,spring配置文件中

          <!-- 加載配置文件 -->
              <context:property-placeholder location="classpath:conf/resource.properties" />

              <context:component-scan base-package="cn.e3mall.sso.controller" />
              <mvc:annotation-driven />
              <bean
                  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                  <property name="prefix" value="/WEB-INF/jsp/" />
                  <property name="suffix" value=".jsp" />
              </bean>
              <mvc:resources location="/css/" mapping="/css/**"/>
              <mvc:resources location="/js/" mapping="/js/**"/>
              <mvc:resources location="/images/" mapping="/images/**"/>

              <!-- 引用dubbo服務 -->
              <dubbo:application name="e3-sso-web"/>
              <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>    
              <dubbo:reference interface="cn.e3mall.sso.service.LoginService" id="loginService" />

          處理流程: 
          1. 傳入用戶名和密碼,調用service層。獲取E3Result。 
          2. 根據(jù)status判斷登錄是否成功 
          3. 從獲得的E3Result中取token信息,存入cookie 
          4. 返回結果給頁面

          /*
           * 用戶登錄處理
           */
          @Controller
          public class LoginController {

              @Autowired
              private LoginService loginService;
              @Value("${TOKEN_KEY}")
              private String TOKEN_KEY;//TOKEN_KEY=token
              @RequestMapping("/page/login")
              public String toLogin(String redirect,Model model){
                  model.addAttribute("redirect", redirect);
                  //返回登錄頁面
                  return "login";
              }

              @RequestMapping(value="/user/login",method=RequestMethod.POST)
              @ResponseBody
              public E3Result login(String username,String password,
                      HttpServletRequest request,HttpServletResponse response){
                  E3Result result = loginService.userLogin(username, password);
                  //判斷是否登錄成功
                  if(result.getStatus()==200){
                      String token = (String) result.getData();
                      //如果登錄成功,token寫入cookie 
                      CookieUtils.setCookie(request, response, TOKEN_KEY, token);
                  }
                  return result;
              }
          }

          注:cookie一般默認是不能跨域的(商城采用了分布式架構,所以每個模塊對應的域名肯定是不一樣的,將比如上面的e3-sso端口號是8089,e3-sso-web是8090),但是這里寫的Cookie工具類CookieUtils的setCookie()方法中對跨域是進行了處理的。

          private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                      String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
                  try {
                      if (cookieValue == null) {
                          cookieValue = "";
                      } else if (isEncode) {
                          cookieValue = URLEncoder.encode(cookieValue, "utf-8");
                      }
                      Cookie cookie = new Cookie(cookieName, cookieValue);
                      if (cookieMaxage > 0)
                          cookie.setMaxAge(cookieMaxage);
                      if (null != request) {// 設置域名的cookie
                          String domainName = getDomainName(request);
                          System.out.println(domainName);
                          if (!"localhost".equals(domainName)) {
                              cookie.setDomain(domainName);
                          }
                      }
                      cookie.setPath("/");
                      response.addCookie(cookie);
                  } catch (Exception e) {
                       e.printStackTrace();
                  }
              }

          到這里工程就算做完了。 
          當用戶登錄的時候,先進行校驗,校驗通過后,生成token,作為key,查出來的用戶信息作為value存入到redis中并設置key的過期時間。并且將token返回給表現(xiàn)層,表現(xiàn)層將token存入Cookie中。當用戶訪問其它模塊,比如訂單模塊的時候,我們可以寫個攔截器,攔截請求,判斷用戶是否登錄,從Cookie中取token,如果沒取到token說明用戶根本沒登錄所以跳轉到登錄頁面,如果取到了token,那么根據(jù)token去redis中查詢用戶信息,說明key已經(jīng)失效了,跳轉到登錄頁面。否則放行。

          比如訪問購物車系統(tǒng)(天貓訪問購物車要求是登錄狀態(tài)下): 
          在e3-order-web工程中編寫攔截器

          /*
           * 用戶登錄處理
           */
          public class LoginInterceptor implements HandlerInterceptor {

              @Autowired
              private TokenService tokenService;

              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                      throws Exception {
                  //前處理,執(zhí)行handler之前執(zhí)行此方法
                  //返回true:放行  false:攔截
                  //1.從cookie中取token
                  String token = CookieUtils.getCookieValue(request, "token");
                  //2.如果沒有token,未登錄狀態(tài)
                  if(StringUtils.isBlank(token)){
                      return true;
                  }
                  //3.如果取到token,需要調用sso系統(tǒng)的服務,根據(jù)token取用戶信息
                  E3Result e3Result = tokenService.getUserByToken(token);
                  if (e3Result.getStatus()!=200){
                      //4.沒有取到用戶信息,登錄已經(jīng)過期,直接放行
                      return true;
                  }
                  //5.取到用戶信息。登錄狀態(tài)。
                  TbUser user = (TbUser) e3Result.getData();
                  //6.把用戶信息放到request中,只需要在controller中判斷request中是否包含user信息。
                  request.setAttribute("user", user);
                  return true;
              }

              public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                      ModelAndView modelAndView) throws Exception {
                  //handler執(zhí)行之后,返回modelAndView之前
              }

              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                      throws Exception {
                  //完成處理,返回modelAndView之后(已經(jīng)響應了)
                  //可以再次處理異常
              }

          }

          注:這里需要在sso系統(tǒng)中發(fā)布一個新的服務

          <dubbo:service interface="cn.e3mall.sso.service.TokenService" 
                  ref="tokenServiceImpl" timeout="600000"/>

          該服務是根據(jù)token取用戶信息

          /*
           * 根據(jù)token取用戶信息
           */
          @Service
          public class TokenServiceImpl implements TokenService{

              @Autowired
              private JedisClient jedisClient;
              @Value("${SESSION_EXPIRE}")
              private Integer SESSION_EXPIRE;

              public E3Result getUserByToken(String token) {
                  //根據(jù)token到redis中取用戶信息
                  String json = jedisClient.get("SESSION:"+ token);
                  if(StringUtils.isBlank(json)){
                      //取不到信息,登錄過期,返回登錄過期
                      return E3Result.build(201, "用戶登錄已經(jīng)過期");
                  }
                  //取到用戶信息,跟新token的過期時間
                  jedisClient.expire("SESSION:"+ token, SESSION_EXPIRE);
                  //返回結果,E3Result其中包含用戶對象
                  TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
                  return E3Result.ok(user); 
              }
          }

          然后在e3-cart-web工程中引用該服務

              <dubbo:reference interface="cn.e3mall.sso.service.TokenService" id="tokenService" />

          測試: 
           
          點擊登錄。提示登錄成功后會跳轉頁面到首頁.
          查看redis 
           





          版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接和本聲明。

          本文鏈接:

          https://blog.csdn.net/qq_37334135/article/details/77727456

          — 【 THE END 】—
          本公眾號全部博文已整理成一個目錄,請在公眾號里回復「m」獲取!

          最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構等等。

          獲取方式:點“在看”,關注公眾號并回復 PDF 領取,更多內容陸續(xù)奉上。

          文章有幫助的話,在看,轉發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  能看的三级网站 | 午夜操逼片 | 色欲影视 淫香淫色 | 无码人妻一区二区三区蜜桃视频 | 12操逼网站 |