Open Aeizzz opened 5 years ago
参考renren-fast 后端更改,把 token 存入redis 进行缓存
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.2.0</version> </dependency>
public class JWTUtil { // 过期时间5分钟 private static final long EXPIRE_TIME = 5*60*1000; /** * 校验token是否正确 * @param token 密钥 * @param secret 用户的密码 * @return 是否正确 */ public static boolean verify(String token, String username, String secret) { try { Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier verifier = JWT.require(algorithm) .withClaim("username", username) .build(); DecodedJWT jwt = verifier.verify(token); return true; } catch (Exception exception) { return false; } } /** * 获得token中的信息无需secret解密也能获得 * @return token中包含的用户名 */ public static String getUsername(String token) { try { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim("username").asString(); } catch (JWTDecodeException e) { return null; } } /** * 生成签名,5min后过期 * @param username 用户名 * @param secret 用户的密码 * @return 加密的token */ public static String sign(String username, String secret) { try { Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME); Algorithm algorithm = Algorithm.HMAC256(secret); // 附带username信息 return JWT.create() .withClaim("username", username) .withExpiresAt(date) .sign(algorithm); } catch (UnsupportedEncodingException e) { return null; } } }
主要用户登陆,验证token
public class JWTToken implements AuthenticationToken { // 密钥 private String token; public JWTToken(String token) { this.token = token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } }
realm 用于处理用户是否合法这一块
看一下实现的 doGetAuthenticationInfo 方法, 目前制作了简单的校验
doGetAuthenticationInfo
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String token = (String) authenticationToken.getPrincipal(); String username = JwtUtils.getUsername(token); // redis 查询用户的token 如果过期则 报错 String red_token = (String) redisTemplate.opsForValue().get(Constant.DEFAULT_TOKEN_KEY + username); if (username == null || StringUtils.isEmpty(username) || red_token == null) { throw new IncorrectCredentialsException("token失效,请重新登录"); } // 否则更新过期时间 redisTemplate.opsForValue().set(Constant.DEFAULT_TOKEN_KEY + username, red_token, SecurityConstants.CODE_TIME, TimeUnit.MINUTES); UserDetail userDetail = new UserDetail(); userDetail.setUser(userService.getUserByLoginUserName(username)); return new SimpleAuthenticationInfo(userDetail, token, getName()); }
我们实现 AuthenticatingFilter 这个类来实现鉴权的方法
AuthenticatingFilter
/** * jwt 过滤器 */ public class JwtFilter extends AuthenticatingFilter { @Override protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception { String token = getRequestToken((HttpServletRequest) request); return new JwtToken(token); } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //获取请求token,如果token不存在,直接返回401 String token = getRequestToken((HttpServletRequest) request); if (StringUtils.isBlank(token)) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); String json = new Gson().toJson(Res.makeErrRsp("invalid token")); httpResponse.getWriter().print(json); return false; } return executeLogin(request, response); } @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { // String authorization = getRequestToken((HttpServletRequest) request); JwtToken token = (JwtToken) createToken(request,response); // 提交给realm进行登入,如果错误他会抛出异常并被捕获 getSubject(request, response).login(token); // 如果没有抛出异常则代表登入成功,返回true return true; } @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { return ((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name()); } @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setContentType("application/json;charset=utf-8"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); try { //处理登录失败的异常 Throwable throwable = e.getCause() == null ? e : e.getCause(); String json = new Gson().toJson(Res.makeErrRsp(throwable.getMessage())); httpResponse.getWriter().print(json); } catch (IOException e1) { } return false; } /** * 获取请求的token */ private String getRequestToken(HttpServletRequest httpRequest) { //从header中获取token String token = httpRequest.getHeader("token"); //如果header中不存在token,则从参数中获取token if (StringUtils.isBlank(token)) { token = httpRequest.getParameter("token"); } return token; } }
里面有几个主要的方法
createToken
onAccessDenied
isAccessAllowed
hey,man,I think it's too simple,you just a little brother!
shiro 接入 jwt
参考renren-fast 后端更改,把 token 存入redis 进行缓存
流程
token 校验流程
依赖
配置jwt
实现Jwttoken
主要用户登陆,验证token
实现realm
realm 用于处理用户是否合法这一块
看一下实现的
doGetAuthenticationInfo
方法, 目前制作了简单的校验重写filter
我们实现
AuthenticatingFilter
这个类来实现鉴权的方法里面有几个主要的方法
createToken
必须要实现的方法 获取请求头的token 来创建出一个JwtToken 对象onAccessDenied
表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。 也就是访问拒绝是获取请求头中的token 来进行验证isAccessAllowed
判断当前是否请求跨域,