它是一种token认证思想,由header,payload,Signature 组成。
header:
包括认证方式以及签名算法
payload:
保存的有效信息,如用户名,用户id等不敏感信息。
Signature:
签名,保证签名的信息没有篡改
优点 自包含:包含一些基础用户信息
简短:适合放在无状态的http协议里面
简单使用com.auth0 java-jwt3.4.0
生成token
String key = "token!Q2W#E$RW";
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 90);
//生成令牌
String token = JWT.create()
.withClaim("username", "张三")//设置自定义用户名
.withExpiresAt(calendar.getTime())//设置过期时间
.sign(Algorithm.HMAC256(key));//设置签名 保密 复杂
//输出令牌
System.out.println(token);
解析token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("token!Q2W#E$RW")).build();
DecodedJWT decodedJWT = jwtVerifier.verify(token);
System.out.println("用户名: " + decodedJWT.getClaim("username").asString()); 、// 存的是时候是什么类型,取得时候就是什么类型,否则取不到值。
System.out.println("过期时间: "+decodedJWT.getExpiresAt());
工具类
public class JWTUtils {
private static String TOKEN = "token!Q@W3e4r";
public static String getToken(Map map){
JWTCreator.Builder builder = JWT.create();
map.forEach((k,v)->{
builder.withClaim(k,v);
});
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,7);
builder.withExpiresAt(instance.getTime());
return builder.sign(Algorithm.HMAC256(TOKEN));
}
public static void verify(String token){
JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token); // 如果验证通过,则不会把报错,否则会报错
}
public static DecodedJWT getToken(String token){
return JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token);
}
}
设置拦截器
public class JWTInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
Map map = new HashMap<>();
try {
JWTUtils.verify(token);
return true;
} catch (TokenExpiredException e) {
map.put("state", false);
map.put("msg", "Token已经过期!!!");
} catch (SignatureVerificationException e){
map.put("state", false);
map.put("msg", "签名错误!!!");
} catch (AlgorithmMismatchException e){
map.put("state", false);
map.put("msg", "加密算法不匹配!!!");
} catch (Exception e) {
e.printStackTrace();
map.put("state", false);
map.put("msg", "无效token~~");
}
String json = new ObjectMapper().writevalueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
//配置器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JwtTokenInterceptor()).
excludePathPatterns("/user/**") // 放行
.addPathPatterns("/**"); // 拦截除了"/user/**的所有请求路径
}
}
SSO
概念
对于单个系统来说认证是很简单,但是对于多个系统来说认证是困难的。如果仅用cookie的域存储来实现会造成较大的难度,比如说系统的跨语言,跨平台等。
所以我们建立SSO统一管理,用Server来监管所有属于同一系统的域系统。
sso-client(所有子系统都应该拥有)
- 拦截子系统未登录用户请求,跳转至sso认证中心
- 接收并存储sso认证中心发送的令牌
- 与sso-server通信,校验令牌的有效性
- 建立局部会话
- 拦截用户注销请求,向sso认证中心发送注销请求
- 接收sso认证中心发出的注销请求,销毁局部会话
sso-server
- 验证用户的登录信息
- 创建全局会话
- 创建授权令牌
- 与sso-client通信发送令牌
- 校验sso-client令牌有效性
- 系统注册
- 接收sso-client注销请求,注销所有会话
1 .在子页面创建登录或许注册拦截,引导进入server系统,并发送系统标识(一般为系统域名)
2.在server页面进行登录,注册操作。生成cookie信息,返回token认证。
3.在跳转其他系统需要进行登录时候,传入token和系统标识到server系统,如果已经认证,则返回登录信息。
注解:sso提高统一的登录和注册页面,其他子系统可以不写注册和登录具体实现<可忽略不看> 1.client创建拦截
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
if (session.getAttribute("isLogin")) {
chain.doFilter(request, response);
return;
}
*//跳转至sso认证中心*
res.sendRedirect("sso-server-url-with-system-url");
}
2.server创建拦截
同上3. 进行登录认证
@RequestMapping("/login")public String login(String username, String password, HttpServletRequest req) { this.checkLoginInfo(username, password); req.getSession().setAttribute("isLogin", true); return "success";}
4.生成token
String token = UUID.randomUUID().toString();
注解:token存在redis里面,通常value为用户信息
5.client收到请求校验token// 请求附带token参数String token = req.getParameter("token");if (token != null) { // 去sso认证中心校验token boolean verifyResult = this.verify("sso-server-verify-url", token); if (!verifyResult) { res.sendRedirect("sso-server-url"); return; } chain.doFilter(request, response);}
6.server 处理子系统请求
7.client校验成功以后创建局部对话
if (verifyResult) { session.setAttribute("isLogin", true);}
8.注销过程
1.cilent 发送logout请求
//clientString logout = req.getParameter("logout");if (logout != null) { this.ssoServer.logout(token);}//server@RequestMapping("/logout")public String logout(HttpServletRequest req) { HttpSession session = req.getSession(); if (session != null) { session.invalidate();//触发LogoutListener } return "redirect:/";}
2.server发送全局注销
sso认证中心有一个全局会话的监听器,一旦全局会话注销,将通知所有注册系统注销。



