单点登陆

用csdn快两年半了 期间在这上面学了不少东西 也非常感谢csdn这个平台 听过一句很不错的话 想要变得更厉害 多看看博客 多写写博客 多分享博客 作为一个菜鸟 用springcolud项目实现单点登陆 分享一下自己写的东西 虽然不是很高端的技术要点 但是我也想用这种方式来记录我的成长

单点登录 用户只需要登陆一次 在访问其他项目的时候不需要再登录

模拟一个商城和一个游戏 以及一个登录中心

当用户访问商城或者游戏 都会检查当前设备是否登陆 这里用token做认证凭证 所以需要用到拦截器进行拦截

注册一个拦截器 去决定让哪些路由不需要被拦截 (一般都是登录 注册不会被拦截)这里模拟一个不被拦截的路由
这个路由比较特殊 因为这个路由不是我们直接调用 而是在登陆中心登录后 重定向回来的路由
不然重定向回来的路由也会被拦截

package com.my.lzy.utils.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@SpringBootConfiguration
public class InterceptorConfig extends WebMvcConfigurerAdapter {

	@Autowired
	private MyInterceptor myInterceptor;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/test/login");
		super.addInterceptors(registry);
	}

}

实现HandlerInterceptor拦截器接口

package com.my.lzy.utils.interceptor;

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

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.my.lzy.utils.token.CookieToken;
import com.my.lzy.utils.token.JwtUtil;

@Component
public class MyInterceptor implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		// 未登录 前往登陆
		String toLogin = "http://127.0.0.1:7000/do/login";

		// 查询是否含有token
		String token = CookieToken.getToken(request, "token");
		System.out.println("从request域中查询token=" + token);
		// 本系统有token时 //验证token是否过期或者错误的token
		boolean flag = JwtUtil.verifyToken(token, "1234");

		// 本系统无token 或者token验证失败 都需要重新前往登陆中心登录
		if (token == null || !flag) {
			response.sendRedirect(toLogin + "?callback=" + request.getRequestURL().toString());
			System.out.println("本系统无token");
			return false;
		}

		// success
		CookieToken.setToken(response, "token", token);
		return true;
	}

	@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

	}

}

当我们访问一个路由的时候 由于没有凭证 所以需要被拦截 到登陆中心进行登录
当然 我们首先要检查用户是否登录过其他项目 如果登录过那我们可以直接返回token 而不需要进行二次登陆
如果用户第一次登录 那我们在登陆成功后把token存入登陆系统中 以便其他项目免登陆

package com.my.lzy.controller;

import java.io.IOException;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.my.lzy.dao.UserMapper;
import com.my.lzy.entity.User;
import com.my.lzy.token.CookieToken;
import com.my.lzy.token.JwtUtil;

@Controller
@RequestMapping("/do")
public class LoginController {

	@Autowired
	private UserMapper userMapper;

	@RequestMapping("/login")
	public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session) {

		String token = CookieToken.getCookie(request, "token");
		System.out.println("token的值=" + token);
		String callback = request.getParameter("callback");
		System.out.println("callable的值=" + callback);
		session.setAttribute("callback", callback);

		// 用户其他端已登陆过
		if (token != null) {

			try {
				response.sendRedirect(callback + "/login?token=" + token);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return "login";
	}

	@RequestMapping("selectUser")
	@ResponseBody
	public String selectUser(String account, String password, HttpServletResponse response, HttpSession session) {

		User u = userMapper.selectUser(account, password);

		if (u != null) {

			String token = JwtUtil.createToken(u, 300000, "1234");
			CookieToken.setCookie(response, "token", token);
			
			Object callable = session.getAttribute("callable");
			String url = (String) callable;
			try {
				response.sendRedirect(url + "/login?token=" + token);
				System.out.println("登陆成功  回调接口并返回token");
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		return "";
	}

}

登陆成功后 会触发我们那个不会被拦截的接口 保存token

package com.my.lzy.controller;

import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.my.lzy.utils.token.CookieToken;

@Controller
public class LoginController {

	
	@RequestMapping("/test/login")
	public String login(String token, HttpServletResponse arg1) {

		System.out.println("商城项目获取到的token=" + token);
		CookieToken.setToken(arg1, "token", token);
		return "test";
	}

}

保存token后访问的页面 没有被拦截说明 token保存下来了
在这里插入图片描述
访问其他几个链接试试 可以发现访问其他几个页面 也没问题 说明token保存成功
在这里插入图片描述启动游戏项目试试
发现并没有访问登陆中心也获取到了token 在这里插入图片描述在这里插入图片描述重启一次后发现 7002端口也访问了登陆中心
在这里插入图片描述由于是菜鸟 所以肯定漏洞百出 感谢各位大佬指出问题

CookieToken类 把token信息存入 cookie 和取出token的工具类

package com.my.lzy.utils.token;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

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

public class CookieToken {

	public static void setToken(HttpServletResponse response, String name, String value) {
		try {
			Cookie cookie = new Cookie(name, URLEncoder.encode(value, "Utf-8"));
			cookie.setPath("/");
			
			response.addCookie(cookie);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
	}

	public static String getToken(HttpServletRequest arg0, String name) {

		Cookie[] cookies = arg0.getCookies();

		if (cookies.length == 0||cookies==null) {

			return null;
		}

		for (Cookie cookie : cookies) {

			if (name.equals(cookie.getName())) {

				try {

					return URLEncoder.encode(cookie.getValue(), "Utf-8");
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		return null;
	}

}

JwtUtil也是一个工具类 用来获取token和验证token的工具类 这个网上有很多模板

package com.my.lzy.utils.token;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Optional;

public class JwtUtil {

	private static final String EXP = "exp";

	private static final String PAYLOAD = "payload";

	private static Logger logger = LoggerFactory.getLogger(JwtUtil.class);

	/**
	 * 加密生成token
	 * 
	 * @param object
	 *            载体信息
	 * @param maxAge
	 *            有效时长
	 * @param secret
	 *            服务器私钥
	 * @param <T>
	 * @return
	 */
	public static <T> String createToken(T object, long maxAge, String secret) {

		try {
			final Algorithm signer = Algorithm.HMAC256(secret);// 生成签名
			String token = JWT.create().withIssuer("签发者").withSubject("用户")// 主题,科目
					.withClaim("userid", 1234).withExpiresAt(new Date(System.currentTimeMillis() + maxAge))
					.sign(signer);

			return token;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("生成token异常:", e);
			return null;
		}
	}

	/**
	 * 解析验证token
	 * 
	 * @param token
	 *            加密后的token字符串
	 * @param secret
	 *            服务器私钥
	 * @return
	 */
	public static Boolean verifyToken(String token, String secret) {

		try {
			Algorithm algorithm = Algorithm.HMAC256(secret);
			JWTVerifier verifier = JWT.require(algorithm).build();
			DecodedJWT jwt = verifier.verify(token);

			return true;
		} catch (Exception e) {

			System.out.println("校验失败");
		}
		return false;
	}
	
	public static <T> T getObject(String token, String secret,Class clazz) {
		return null;

	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值