SSO(單點登入)MD5加鹽 原理案例教程 火推

qq1350048638發表於2018-02-24

SSO(單點登入)後期用redis儲存
user伺服器放到tokenManager 儲存tonken
原始碼下載:https://gitee.com/qq1350048638/lj_user_server

重點的幾個類程式碼展示出來


前端login.jsp 登入時 通過session儲存tonken

$.ajax({
                url:"http://localhost:8881/user/token",
                type:"post",
                data:{"name":username,"password":password},
                dataType:"json",
                success:function(result){
                    if(result.status==1){//成功
                        sessionStorage.token = result.data.token;//獲取令牌值
                        window.parent.location.reload();//重新整理當前頁
                    }else if(result.status==2){//使用者錯
                        $("#username_error").html(result.msg);
                    }else if(result.status==3){//密碼錯
                        $("#password_error").html(result.msg);
                    }
                }
            });

UserServer 工程裡面結構

這裡寫圖片描述


.user.controller類

package com.lj.ovls.user.controller;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.lj.ovls.common.entity.ResponseResult;
import com.lj.ovls.user.service.UserService;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value="/user/token",method=RequestMethod.POST)
    public ResponseResult createToken(String name,String password,HttpSession session){
        ResponseResult result = 
            userService.createToken(name, password);
//      if(result.getStatus()==1){//成功,才會有token值
//          //將token存入session
//          Map<String, Object> data = (Map)result.getData();
//          session.setAttribute("token",data.get("token"));
//      }
        return result;
    }

    @RequestMapping(value="/user/token",method=RequestMethod.GET)
    public ResponseResult checkToken(String token){
        ResponseResult result = 
            userService.checkToken(token);
        return result;
    }


}

Token實體類

public class Token {  
    private int userId;//登入使用者名稱  
    private Date expired; //過期時間  
    private Date lastOperate; // 最近一次操作的時間  
    ...省略get set
}

UserServiceImpl類
將使用者密碼加鹽後和資料庫密碼進行比較

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userDao;

    @Autowired
    private TokenManager tokenManager;

    @Override
    public ResponseResult createToken(
            String name, String password) {
        ResponseResult result = new ResponseResult();

        //檢查賬號和密碼正確性
        User user = userDao.selectByName(name);
        if(user == null){
            result.setStatus(2);
            result.setMsg("使用者不存在");
            return result;
        }
        //檢測密碼
        //將使用者輸入密碼+salt進行md5處理
        String md5Password = Md5Utils.md5(password+user.getSalt());
        if(!user.getPassword().equals(md5Password)){
            result.setStatus(3);
            result.setMsg("密碼不正確");
            return result;
        }
        //賬號和通過檢測
        result.setStatus(1);
        result.setMsg("登入成功");
        //生成一個token
        String token = TokenUtil.generatorToken(user.getId());
        tokenManager.addToken(token, user.getId());
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("token", token);
        result.setData(data);
        return result;
    }

    @Override
    public ResponseResult checkToken(String token) {
        ResponseResult result = new ResponseResult();
        boolean ok = tokenManager.validate(token);
        if(ok){//token通過驗證
            result.setStatus(1);
            result.setMsg("token令牌合法");
            //將最後一次操作時間更新下
            tokenManager.updateLastOperate(token);
        }else{
            result.setStatus(2);
            result.setMsg("token令牌不合法");
        }
        return result;
    }

}

Md5加密工具類

public class Md5Utils {
    public static byte[] md5(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            md.update(data);
            return md.digest();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return new byte[] {};

    }

    public static String md5(String data) {
        try {
            byte[] md5 = md5(data.getBytes("utf-8"));
            return toHexString(md5);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String toHexString(byte[] md5) {
        StringBuilder buf = new StringBuilder();
        for (byte b : md5) {
            buf.append(leftPad(Integer.toHexString(b & 0xff), '0', 2));
        }
        return buf.toString();
    }

    public static String leftPad(String hex, char c, int size) {
        char[] cs = new char[size];
        Arrays.fill(cs, c);
        System.arraycopy(hex.toCharArray(), 0, cs, cs.length - hex.length(),
                hex.length());
        return new String(cs);
    }

    /**
     * test
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(md5("1234561296cd20"));
    }

}

TokenManager類

@Component
public class TokenManager {  

    //令牌儲存結構 ConcurrentHashMap
    public Map<String, Token> tokenMap = 
            new ConcurrentHashMap<String, Token>();  

    /**
     * 令牌有效性驗證 
     * @param stoken 使用者令牌
     * @return true有效;false失效
     */
    public boolean validate(String stoken) {  
        System.out.println("Token驗證");  
        if(tokenMap.containsKey(stoken)){ //令牌存在 
            Token token =  tokenMap.get(stoken);
            Date expired = token.getExpired();
            Date now = new Date();  
            if(now.compareTo(expired) > 0){//已過期    
                tokenMap.remove(stoken);//移除  
            }else{//未過期
                return true;
            }
         }
        return false;  
    }  

   /**
    * 使用者授權成功後存入授權資訊 
    * @param stoken 使用者令牌
    * @param userId 使用者ID
    */
    public void addToken(String stoken, int userId) {  
        Token token = new Token();  
        token.setUserId(userId); 
        token.setLastOperate(new Date());  
        token.setExpired(new Date(token.getLastOperate().getTime() + 2 * 60 * 1000));  

        tokenMap.put(stoken, token);  
    }  

   /**
    * 更新token最近一次操作的時間和有效期期 
    * @param stoken 使用者令牌
    */
    public void updateLastOperate(String stoken) {  
        Token token = tokenMap.get(stoken);  
        token.setLastOperate(new Date());  
        token.setExpired(new Date(token.getLastOperate().getTime() + 2 * 60 * 1000));  
    }  

}  

TokenManagerTask類

/**
 * 定期清除token列表中過期的令牌
 * @author Administrator
 *
 */
@Component
@EnableScheduling
public class TokenManagerTask {

    @Autowired
    private TokenManager tokenManager;

    @Scheduled(cron="1/5 * * * * ?")
    public void manager(){
//      System.out.println("定時清除過期令牌");
        Map<String, Token> tokenMap = tokenManager.tokenMap;
        for(Entry<String, Token> entiy : tokenMap.entrySet()) {  
            String stoken = entiy.getKey();  
            Token token = entiy.getValue();  
            Date expired = token.getExpired();  
            Date now = new Date();  
//          System.out.println("token列表:"+stoken+" 有效期:"+expired+" 授權時間:"+token.getLastOperate());
            //當前時間大於過期時間,說明標識已經過期時間,將token移除  
            if(now.compareTo(expired) > 0) {  
             //已過期,清除  
                 tokenMap.remove(stoken);  
//               System.out.println("清除了:"+stoken+" 清除時間:"+now);
            }
        } 
    }

}

TokenUtil 類

public class TokenUtil {

    /**
     * 生成一個令牌號
     * @return 令牌號
     */
    public static String generatorToken(int userId){
        UUID uuid = UUID.randomUUID();
        return uuid.toString()+"-"+userId;
    }

    public static void main(String[] args){
        System.out.println(generatorToken(12));
    }
}

另外一個工程裡面進行驗證
paper工程

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class InterceptorsConfig extends WebMvcConfigurerAdapter{


    @Autowired
    private CheckLoginInterceptor checkLogin;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(checkLogin).addPathPatterns("/paper/subject/*");
    }
}

paper類

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import ovls.common.entity.ResponseResult;
import ovls.paper.remote.UserServiceRemote;


@Component
public class CheckLoginInterceptor implements HandlerInterceptor{

//  @Autowired
//  private RestTemplateBuilder restBuilder;
//  @Autowired
//  private RestTemplate restTemplate;

    @Autowired
    private UserServiceRemote userRemote;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //獲取請求帶過來的token
        String token = request.getParameter("token");
        System.out.println("呼叫/user/token服務檢查token是否合法"+token);
        response.setContentType("application/json;charset=UTF-8");


        if(token != null && !"".equals(token)){
            //呼叫/user/token服務檢查token是否合法,合法就返回true,不合法返回false
//          RestTemplate restTemplate = restBuilder.build();
            //呼叫ovls_course_server的服務查詢所有學科資訊
//          ResponseResult userResult  = restTemplate.getForObject(
//              "http://USERSERVER/user/token?token="+token, ResponseResult.class);
            //利用Feign介面呼叫服務
            ResponseResult userResult = userRemote.checkToken(token);
            if(userResult.getStatus()==1){//通過驗證,表示token合法
                return true;
            }
        }
        //未通過驗證
        PrintWriter out = response.getWriter();
        out.println("{\"stauts\":2,\"msg\":\"不合法使用者\"}");
        out.close();
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }

}

相關文章