1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 44360字,需瀏覽 89分鐘

         ·

        2021-05-25 21:08

        點擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

        優(yōu)質(zhì)文章,第一時間送達(dá)

        76套java從入門到精通實戰(zhàn)課程分享

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

        為什么要單點登錄

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

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

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

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

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

        前期準(zhǔn)備好的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相關(guān) -->
                <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中:配置事務(wù)

        <!-- 事務(wù)管理器 -->
            <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,構(gòu)造方法太多用index容易錯 -->
                <constructor-arg name="host" value="192.168.25.128"/>
                <constructor-arg name="port" value="6379"/>
            </bean>

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

        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中設(shè)置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相關(guān) -->
            <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相關(guān) -->
                <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配置文件中除了組件掃描之外還要引用服務(wù),但是Service層還沒發(fā)布服務(wù),所以待會給出,另外還需要將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的配置文件默認(rèn)在: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) 
        服務(wù)層:e3-sso-service中

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

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

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

        4. 設(shè)置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必不重復(fù)
                //4.把用戶信息寫入redis,key:token,value:用戶信息
                user.setPassword(null);
                jedisClient.set("SESSION:"+ token, JsonUtils.objectToJson(user));
                //5.設(shè)置Session的過期時間
                jedisClient.expire("SESSION:"+ token, SESSION_EXPIRE);
                //6.把token返回
                return E3Result.ok(token);
            }
        }

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

        E3Result為自定義響應(yīng)類,如下

        public class E3Result implements Serializable{

            // 定義jackson對象
            private static final ObjectMapper MAPPER = new ObjectMapper();
            // 響應(yīng)業(yè)務(wù)狀態(tài)
            private Integer status;
            // 響應(yīng)消息
            private String msg;
            // 響應(yīng)中的數(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方法
           }

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

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

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

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

        表現(xiàn)層:e3-sso-web中 
        先要接收服務(wù),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服務(wù) -->
            <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. 傳入用戶名和密碼,調(diào)用service層。獲取E3Result。 
        2. 根據(jù)status判斷登錄是否成功 
        3. 從獲得的E3Result中取token信息,存入cookie 
        4. 返回結(jié)果給頁面

        /*
         * 用戶登錄處理
         */
        @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一般默認(rèn)是不能跨域的(商城采用了分布式架構(gòu),所以每個模塊對應(yīng)的域名肯定是不一樣的,將比如上面的e3-sso端口號是8089,e3-sso-web是8090),但是這里寫的Cookie工具類CookieUtils的setCookie()方法中對跨域是進(jìn)行了處理的。

        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) {// 設(shè)置域名的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();
                }
            }

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

        比如訪問購物車系統(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,需要調(diào)用sso系統(tǒng)的服務(wù),根據(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)響應(yīng)了)
                //可以再次處理異常
            }

        }

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

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

        該服務(wù)是根據(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);
                //返回結(jié)果,E3Result其中包含用戶對象
                TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
                return E3Result.ok(user); 
            }
        }

        然后在e3-cart-web工程中引用該服務(wù)

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

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





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

        本文鏈接:

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






        粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

        ??????

        ??長按上方微信二維碼 2 秒


        感謝點贊支持下哈 

        瀏覽 49
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            xxxx日本老师29hd | 九色毛片| 色男人天堂| www豆花视频com | 久久精品2021 | 淫淫视频 | 国产午夜精华视频 | 99热最新国产 | 婷婷情色五月天 | 激情福利社|