zoukankan      html  css  js  c++  java
  • sso单点登录系统

    sso单点登录概念

    1.一处登录,处处登录.会单独做一个单点登录系统,只负责颁发token和验证token,和页面登录功能.

    2.通过在浏览器cookie中放入token,和在redis中对应token放入用户信息的方式,代替session共享,使用jwt(json web token)自定义一个携带用户信息token加密算法.

    3.cookie中的token是已经使用过的token,取名oldToken . url地址栏中的token新颁发的token,取名newToken

    做法:

    1.首先自定义一个注解,作用在方法上.有3种状态:

    1.1 如果为null,表示直接放行,例如商品详情页,用户可以不用登录直接访问.

    1.2 如果为false,经常用在购物车方法上,表示可登录可不登录,用户不登录购物车数据保存cookie中,用户登录数据保存数据库并放redis一份.

    1.3 如果为true,表示用户必须登录,例如购物车结算跳订单页面.

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LoginRequired {

      boolean isNeededSuccess() default true;

    }

     

    2.自定义拦截器,并加入到springr容器中

    @Configuration
    public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
      @Autowired
      AuthInterceptor authInterceptor;

      @Override
      public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(authInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
      }
    }

    @Component
    public class AuthInterceptor extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    HandlerMethod hm = (HandlerMethod)handler;

    LoginRequired methodAnnotation = hm.getMethodAnnotation(LoginRequired.class);

    if(methodAnnotation==null){
    return true;
    }else{
    // 先获得用户cookie中关于用户的身份token
    //token有四种情况
    String token = "";

    String oldToken = CookieUtil.getCookieValue(request, "oldToken", true);
    if(StringUtils.isNotBlank(oldToken)){
    token = oldToken;
    }
    String newToken = request.getParameter("newToken");
    if(StringUtils.isNotBlank(newToken)){
    token = newToken;
    }


    if(StringUtils.isNotBlank(token)){
    // 验证用户的token是否正确
    // 通过远程ws请求认证中心,验证token
    String requestUrl = "http://passport.gmall.com:8090/verify?token="+token+"&currentIp="+request.getRemoteAddr();
    String successJSON = HttpclientUtil.doGet(requestUrl);
    HashMap<String,String> hashMap = new HashMap<>();
    HashMap hashMapJSON = JSON.parseObject(successJSON, hashMap.getClass());

    if(hashMapJSON!=null&&hashMapJSON.get("success").equals("success")){
    // 重新更新cookie的过期时间
    CookieUtil.setCookie(request,response,"oldToken",token,60*60,true);
    request.setAttribute("memberId",hashMapJSON.get("memberId"));
    request.setAttribute("nickname",hashMapJSON.get("nickname"));
    return true;
    }else{
    if(methodAnnotation.isNeededSuccess()){
    String ReturnUrl = request.getRequestURL().toString();
    response.sendRedirect("http://passport.gmall.com:8090/index?ReturnUrl="+ReturnUrl);
    // 拦截验证
    return false;
    }
    }
    }else{
    if(methodAnnotation.isNeededSuccess()) {
    String ReturnUrl = request.getRequestURL().toString();
    response.sendRedirect("http://passport.gmall.com:8090/index?ReturnUrl=" + ReturnUrl);
    // 拦截验证
    return false;
    }
    }
    }

    return true;

    }
    }


    3.单点登录系统代码

    @Controller
    public class passportController {

    @Reference
    UserService userService;

    @RequestMapping("vlogin")
    public String vlogin(String code, HttpServletRequest request) {

    // 换取access_token
    String access_token_url = "https://api.weibo.com/oauth2/access_token?client_id= 25920146&client_secret=dc8de1392f642a01259b136ff8e970b9&grant_type=authorization_code&redirect_uri=http://passport.gmall.com:8090/vlogin&code=e211655dd6c78a66fcfcfdff552424f6";

    Map<String,String> map = new HashMap<String,String>();
    map.put("client_id","25920146");
    map.put("client_secret","dc8de1392f642a01259b136ff8e970b9");
    map.put("grant_type","authorization_code");
    map.put("redirect_uri","http://passport.gmall.com:8090/vlogin");
    map.put("code",code);
    String access_json = HttpclientUtil.doPost("https://api.weibo.com/oauth2/access_token", map);
    System.out.println(access_json);

    Map<String,String> map_access_json = new HashMap<String,String>();
    Map access_map = JSON.parseObject(access_json, map_access_json.getClass());


    // 获得第三方用户数据
    String access_token = (String)access_map.get("access_token");
    String uid = (String)access_map.get("uid");// uid uidStr
    UmsMember umsMember = new UmsMember();
    umsMember = userService.isUidExists(uid);

    if(umsMember==null){

    String show_url = "https://api.weibo.com/2/users/show.json?access_token="+access_token+"&uid="+uid;

    String user_json = HttpclientUtil.doGet(show_url);
    Map<String,String> map_user_json = new HashMap<String,String>();
    Map user_map = JSON.parseObject(user_json, map_user_json.getClass());
    System.out.println(user_map);

    // 存入数据库
    umsMember.setNickname((String)user_map.get("screen_name"));
    umsMember.setUsername((String)user_map.get("name"));
    umsMember.setSourceType("2");
    umsMember.setSourceUid((String)user_map.get("idstr"));
    umsMember.setCreateTime(new Date());
    umsMember.setAccessToken(access_token);
    umsMember.setAccessCode(code);
    umsMember = userService.addUser(umsMember);
    }


    // 根据用户信息生成token
    String key = "houruisso";
    String ip = request.getRemoteAddr();
    Map<String,Object> token_map = new HashMap<>();
    token_map.put("nickname",umsMember.getNickname());
    token_map.put("memberId",umsMember.getId());
    String token = JwtUtil.encode(key, token_map, ip);

    // 将生成的token和登录用户信息保存在缓存中一分
    userService.addUserCache(token,umsMember);
    return "redirect:http://search.gmall.com:8083/index?newToken="+token;
    }

    @RequestMapping("login")
    @ResponseBody
    public String login(UmsMember umsMember, HttpServletRequest request) {
    System.out.println("用户登录,验证用户名和密码是否正确");

    // 调用用户服务userService,验证用户名和密码
    UmsMember umsMemberFromDb = userService.login(umsMember);

    if (umsMemberFromDb == null) {
    return "fail";
    } else {
    // 根据已经登录的用户信息和,服务器密钥,和其他盐值(根据系统算法)生成一个token
    String key = "atguigusso";
    String ip = request.getRemoteAddr();
    //String ip = request.getHeader("x-forward-for");//nginx
    Map<String, Object> map = new HashMap<>();
    map.put("nickname", umsMemberFromDb.getNickname());
    map.put("memberId", umsMemberFromDb.getId());
    String token = JwtUtil.encode(key, map, ip);

    // 将生成的token和登录用户信息保存在缓存中一分
    userService.addUserCache(token,umsMemberFromDb);

    return token;
    }


    }

    @RequestMapping("verify")
    @ResponseBody
    public String verify(String token, String currentIp) {
    System.out.println("认证中心认证用户的token");


    String key = "houruisso";

    String ip = currentIp;

    Map<String, Object> map = JwtUtil.decode(token, key, ip);


    Map<String,String> verifyReturn = new HashMap<>();
    if (map != null) {
    verifyReturn.put("success","success");
    verifyReturn.put("memberId",(String)map.get("memberId"));
    verifyReturn.put("nickname",(String)map.get("nickname"));
    return JSON.toJSONString(verifyReturn);
    } else {
    verifyReturn.put("success","fail");
    return JSON.toJSONString(verifyReturn);
    }


    }

    @RequestMapping("index")
    public String index(String ReturnUrl, ModelMap modelMap) {
    System.out.println("认证中心首页");

    modelMap.put("ReturnUrl", ReturnUrl);
    return "index";
    }
    }


    4.前端代码
    <!--底部-->
    <input type="text" id="ReturnUrl" th:value="${ReturnUrl}"/><br />


    </body>
    <script language="JavaScript">

    function submitLogin() {
    var username = $("#username").val();
    var password = $("#password").val();
    $.post("login",{username:username,password:password},function(token){
    if(token=="fail"){
    alert("登录失败,用户名和密码错误");
    }else{
    window.location.href=$("#ReturnUrl").val()+"?newToken="+token;
    }
    });
    }



    @Override
    public void addUserCache(String token, UmsMember umsMemberFromDb) {
    String tokenKey = "user:"+umsMemberFromDb.getId()+":token";
    String userKey = "user:"+umsMemberFromDb.getId()+":info";

    Jedis jedis = null;

    jedis = redisUtil.getJedis();

    jedis.setex(tokenKey,60*60,token);
    jedis.setex(userKey,60*60, JSON.toJSONString(umsMemberFromDb));

    jedis.close();
    }









  • 相关阅读:
    【文言文】从高考到程序员
    lambda方法引用总结——烧脑吃透
    秒杀苹果carplay baidu车联网API冷艳北京车展
    东君误妾我怜卿(一)
    百度快照投诉技巧案例分析百度快照就是这样刷出来的
    新浪博客是否可以放谷歌广告?如何添加
    与葡萄酒的亲密接触-选购技巧篇
    车联网高速公路智能交通解决方案
    物联网细分领域-车联网(OBD)市场分析
    APP开发选择什么框架好? 请看这里!
  • 原文地址:https://www.cnblogs.com/liuyi13535496566/p/11576085.html
Copyright © 2011-2022 走看看