第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第十天】(單點登陸系統實現)

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040html

第04項目:淘淘商城(SpringMVC+Spring+Mybatis) 的學習實踐總結【第六天】java

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第七天】(redis緩存)redis

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第八天】(solr服務器搭建、搜索功能實現)spring

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第九天】(商品詳情頁面實現)數據庫

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第十天】(單點登陸系統實現)json

 

2   課程計劃瀏覽器

一、單點登陸系統SSO緩存

a)       建立單點登陸系統,獨立的工程。服務器

b)       發佈登陸、註冊的接口cookie

c)       單點登陸系統實現登陸、註冊功能。


3  什麼是單點登陸系統

3.1   什麼是SSO

SSO英文全稱Single Sign On,單點登陸。SSO是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。它包括能夠將此次主要的登陸映射到其餘應用中用於同一個用戶的登陸的機制。它是目前比較流行的企業業務整合的解決方案之一。

3.2   傳統的登陸流程

 

 

3.2.1   傳統流程中的問題:

在集羣環境中。須要把同一套代碼部署到多臺服務器上。每一個工程都有本身獨立的session

 

在集羣環境中每一個工程都有本身的session,若是把用戶信息寫入session而不共享的話,會出現用戶反覆登陸的狀況。


第二種方案

實現單點登陸系統,提供服務接口。把session數據存放在redis。

Redis能夠設置key的生存時間、訪問速度快效率高。

優勢:redis存取速度快,不會出現多個節點session複製的問題。效率高。

SSO單點登陸系統通常流程

 

 

 

4   建立單點登陸系統

單點登陸系統是一個獨立的工程。須要操做redis、鏈接數據庫。

 

 註冊以前的數據校驗

Service層

/**
 * 用戶管理Service
 * 
 * @author kangy
 *
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private TbUserMapper userMapper;

    @Override
    public TaotaoResult checkData(String content, Integer type) {
        // 建立查詢條件
        TbUserExample example = new TbUserExample();
        TbUserExample.Criteria criteria = example.createCriteria();

        // 對數據進行校驗:一、二、3分別表明username、phone、email
        if (1 == type) {
            criteria.andUsernameEqualTo(content);

        } else if (2 == type) {
            criteria.andPhoneEqualTo(content);

        } else {
            criteria.andEmailEqualTo(content);
        }
        // 執行查詢
        List<TbUser> list = userMapper.selectByExample(example);

        if (list == null || list.size() == 0) {
            return TaotaoResult.ok(true);
        }

        return TaotaoResult.ok(false);
    }

    @Override
    public TaotaoResult createUser(TbUser user) {
        user.setUpdated(new Date());
        user.setCreated(new Date());
        //spring框架的MD5工具加密
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        userMapper.insert(user);
        return TaotaoResult.ok();
    }
    
    
}

 

5.1.4    Controller層

從url中接收兩個參數,調用Service進行校驗,在調用Service以前,先對參數進行校驗,例如type必須是一、二、3其中之一。

返回TaotaoResult。須要支持jsonp。

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;


    @SuppressWarnings({ "deprecation" })
    @RequestMapping("/check/{param}/{type}")
    public Object checkData(@PathVariable String param, @PathVariable Integer type, String callback) {

        TaotaoResult result = null;

        // 參數有效性校驗
        if (StringUtils.isBlank(param)) {
            result = TaotaoResult.build(400, "校驗內容參數不能爲空!");
        }
        if (type == null) {
            result = TaotaoResult.build(400, "校驗內容類型不能爲空!");
        }
        if (type != 1 & type != 2 & type != 3) {
            result =  TaotaoResult.build(400, "校驗內容類型錯誤");
        }

        // 校驗出錯
        if (null != result) {
            if (null != callback) {
                MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
                mappingJacksonValue.setJsonpFunction(callback);
                return mappingJacksonValue;
            } else {
                return result;
            }
        }

        // 調用服務
        try {
            result = userService.checkData(param, type);
        } catch (Exception e) {
            result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }

        if (null != callback) {
            MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
            mappingJacksonValue.setJsonpFunction(callback);
            return mappingJacksonValue;
        } else {
            return result;
        }

    }
    
    
    //建立用戶的方法
    @RequestMapping("/register")
    public TaotaoResult createUser(TbUser user) {
        try {
            TaotaoResult result = userService.createUser(user);
            return result;
            
        } catch (Exception e) {
            return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }
        
        
    }

}

 

6   用戶登陸接口

是一個post請求,包含用戶和密碼。接收用戶名和密碼,到數據庫中查詢,根據用戶名查詢用戶信息,查到以後進行密碼比對,須要對密碼進行md5加密後進行比對。比對成功後說明登陸成功,須要生成一個token可使用UUID。須要把用戶信息寫入redis,key就是token,value就是用戶信息。返回token字符串。

是一個post請求,包含用戶和密碼。接收用戶名和密碼,到數據庫中查詢,根據用戶名查詢用戶信息,查到以後進行密碼比對,須要對密碼進行md5加密後進行比對。比對成功後說明登陸成功,須要生成一個token可使用UUID。須要把用戶信息寫入redis,key就是token,value就是用戶信息。返回token字符串。

    //用戶登陸
    @Override
    public TaotaoResult userLogin(String username, String password,
            HttpServletRequest request ,HttpServletResponse response) {
        // 建立查詢條件
        TbUserExample example = new TbUserExample();
        TbUserExample.Criteria criteria = example.createCriteria();
        criteria.andUsernameEqualTo(username);
        // 執行查詢
        List<TbUser> list = userMapper.selectByExample(example);
        //若是爲空沒有此用戶名
        if(list == null || list.size() == 0) {
            return TaotaoResult.build(400, "用戶名錯誤:不存在");
        }
        TbUser user = list.get(0);
        //System.out.println(user.getPassword());
        String pwd = DigestUtils.md5DigestAsHex(password.getBytes()); //字符串比較用.equals()方法
        if( !pwd.equals(user.getPassword()) ) {
            //控制檯輸入對比一下
            //System.out.println(DigestUtils.md5DigestAsHex(password.getBytes()));
            
            return TaotaoResult.build(400, "輸入的密碼錯誤。");
        }
        
        //生成token
        String token = UUID.randomUUID().toString();
        //存以前把密碼清空
        user.setPassword(null);
        //把用戶信息寫入redis
        jedisClient.set( REDIS_USER_SESSION_KEY + ":" + token, JsonUtils.objectToJson(user));
        //設置緩存過時時長
        jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
        
        //添加寫cookie的邏輯,此處設置是關閉瀏覽器就失效
        CookieUtils.setCookie(request, response, "TT_TOKEN", token);
        //返回token
        return TaotaoResult.ok(token);
    }

 

 

 

6.3   Controller層

接收表單,包含用戶、密碼。調用Service進行登陸返回TaotaoResult。

    //用戶登陸
    @PostMapping("/login")
    @ResponseBody
    public TaotaoResult userLogin(String username,String password) {
        
        try {
            TaotaoResult result = userService.userLogin(username, password);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }
    }
package com.taotao.common.utils;

import java.io.PrintWriter;
import java.io.StringWriter;

public class ExceptionUtil {

    /**
     * 獲取異常的堆棧信息
     * 
     * @param t
     * @return
     */
    public static String getStackTrace(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);

        try {
            t.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }
}

 


12.根據token取用戶信息

7  經過token查詢用戶信息

7.1   業務分析

根據token判斷用戶是否登陸或者session是否過時。接收token,根據token到redis中取用戶信息。判斷token字符串是否對應用戶信息,若是不對應說明token非法或者session已過時。取到了說明用戶就是正常的登陸狀態。返回用戶信息,同時重置用戶的過時時間。

7.2   Dao層

使用JedisClient實現類。

7.3   Service層

接收token,調用dao,到redis中查詢token對應的用戶信息。返回用戶信息並更新過時時間。

 

    @Override
    public TaotaoResult getUserByToken(String token) {
        
        //根據token從redis緩存中查詢用戶信息
        String json = jedisClient.get(REDIS_USER_SESSION_KEY + ":" + token);
        //判斷是否爲空
        if(StringUtils.isBlank(json)) {
            return TaotaoResult.build(400, "此session已過時,請從新登陸");
        }else {
            //再次設置過時時長
            jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);        
        }
        
        //返回用戶信息
        return TaotaoResult.ok(JsonUtils.jsonToPojo(json, TbUser.class));
        
    }

7.4    Controller層

接收token調用Service返回用戶信息,使用TaotaoResult包裝。

請求的url:

http://sso.taotao.com/user/token/{token}

    @SuppressWarnings({ "deprecation" })
    @PostMapping("/token/{token}")
    public Object getUserByToken(@PathVariable String token , String callback) {
        TaotaoResult result = null;
        try {
            TaotaoResult taotaoResult = userService.getUserByToken(token);
            result = taotaoResult;
        } catch (Exception e) {
            e.printStackTrace();
            result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }

        // 判斷是否爲jsonp調用
        if (StringUtils.isBlank(callback)) {
            return result;
        } else {
            MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
            mappingJacksonValue.setJsonpFunction(callback);
            return mappingJacksonValue;
        }

    }

 

 

=======================================

參考資料:

 

end

相關文章
相關標籤/搜索