当前位置 主页 > 服务器问题 > Linux/apache问题 >
到这里shiro配置就全部完成了
下面开始配置jwt:
首先我们需要重写 AuthenticationToken接口 此接口的作用
负责把shiro中username,password生成用于验证的token的封装类
所有我们需要去实现这个接口,封装我们自己生成的JWT生成的token
import org.apache.shiro.authc.AuthenticationToken; /** * AuthenticationToken: shiro中负责把username,password生成用于验证的token的封装类 * 我们需要自定义一个对象用来包装token。 */ public class JwtToken implements AuthenticationToken { private String token; public JwtToken(String token) { this.token = token; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } @Override public Object getPrincipal() { return null; } @Override public Object getCredentials() { return null; } }
因为我们是前后端分离项目所有我们不存在session验证之类的 所有每次请求都需要携带token,所以每次请求我们都需要去验证token的真实性,所有我们需要去实现 BasicHttpAuthenticationFilter过滤器
BasicHttpAuthenticationFilter继承 AuthenticatingFilter 过滤器其能够自动地进行基于所述传入请求的认证尝试。此实现是每个基本HTTP身份验证规范的Java实现 , 通过此过滤器得到HTTP请求资源获取Authorization传递过来的token参数 获取subject对象进行身份验证
代码如下:
import com.alibaba.fastjson.JSONObject; import com.serverprovider.config.shiro.jwt.JwtToken; import com.util.Util.utilTime; import org.apache.log4j.Logger; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.TimeUnit; /** * * BasicHttpAuthenticationFilter继承 AuthenticatingFilter 过滤器 * 其能够自动地进行基于所述传入请求的认证尝试。 * BasicHttpAuthenticationFilter 基本访问认证过滤器 * 此实现是每个基本HTTP身份验证规范的Java实现 * 通过此过滤器得到HTTP请求资源获取Authorization传递过来的token参数 * 获取subject对象进行身份验证 * * */ public class JwtFilter extends BasicHttpAuthenticationFilter { Logger logger = Logger.getLogger(JwtFilter.class); /** * 应用的HTTP方法列表配置基本身份验证筛选器。 * 获取 request 请求 拒绝拦截登录请求 * 执行登录认证方法 * * @param request * @param response * @param mappedValue * @return */ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String requestURI = httpServletRequest.getRequestURI(); if (requestURI.equals("/user/login/verifyUser") || requestURI.equals("/user/register")) { return true; } else { try { executeLogin(request, response); return true; } catch (Exception e) { e.printStackTrace(); return false; } } } /** * Authorization携带的参数为token * JwtToken实现了AuthenticationToken接口封装了token参数 * 通过getSubject方法获取 subject对象 * login()发送身份验证 * * 为什么需要在Filter中调用login,不能在controller中调用login? * 由于Shiro默认的验证方式是基于session的,在基于token验证的方式中,不能依赖session做为登录的判断依据. * @param request * @param response */ @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { HttpServletResponse httpServletResponse = (HttpServletResponse) response; try{ HttpServletRequest httpServletRequest = (HttpServletRequest) request; String token = httpServletRequest.getHeader("Authorization"); JwtToken jwtToken = new JwtToken(token); // 提交给realm进行登入,如果错误他会抛出异常并被捕获 Subject subject = getSubject(request, response); subject.login(jwtToken); logger.info("JWT验证用户信息成功"); // 如果没有抛出异常则代表登入成功,返回true return true; }catch (Exception e){ /* * * 这个问题纠结了好久 * 原生的shiro验证失败会进入全局异常 但是 和JWT结合以后却不进入了 之前一直想不通 * 原因是 JWT直接在过滤器里验证 验证成功与否 都是直接返回到过滤器中 成功在进入controller * 失败直接返回进入springboot自定义异常处理页面 */ JSONObject responseJSONObject = new JSONObject(); responseJSONObject.put("result","401"); responseJSONObject.put("resultCode","token无效,请重新获取。"); responseJSONObject.put("resultData","null"); responseJSONObject.put("resultTime", utilTime.StringDate()); PrintWriter out = null; httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json; charset=utf-8"); logger.info("返回是"); logger.info(responseJSONObject.toString()); out = httpServletResponse.getWriter(); out.append(responseJSONObject.toString()); } return false; } /** * 对跨域提供支持 */ @Override protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态 if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { httpServletResponse.setStatus(HttpStatus.OK.value()); return false; } return super.preHandle(request, response); } }