微服務專案中怎麼讓登入使用者資訊共享
阿新 • • 發佈:2021-08-22
微服務專案中怎麼讓登入使用者資訊共享
無論是token還是jwt,核心就是獲取登入資訊,然後放到SecurityContextHolder.getContext().setAuthentication(authResult)中。
token
token的話,只要在資源伺服器中,進行校驗token,底層程式碼中會把OAuth2Authentication放到SecurityContextHolder.getContext()中,這裡的程式碼在上一篇部落格有寫,這裡就不貼出來了。
使用者資訊如下:
jwt
認證伺服器登入成功使用者。往響應頭中新增token資訊
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager; private RsaKeyProperties prop; public JwtLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) { this.authenticationManager = authenticationManager; this.prop = prop; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { SysUser sysUser = new ObjectMapper().readValue(request.getInputStream(), SysUser.class); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword()); return authenticationManager.authenticate(authRequest); }catch (Exception e){ try { response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); PrintWriter out = response.getWriter(); Map resultMap = new HashMap(); resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED); resultMap.put("msg", "使用者名稱或密碼錯誤!"); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); }catch (Exception outEx){ outEx.printStackTrace(); } throw new RuntimeException(e); } } @Override public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { SysUser user = new SysUser(); user.setUsername(authResult.getName()); user.setRoles((List<SysRole>) authResult.getAuthorities()); String token = JwtUtils.generateTokenExpireInMinutes(user, prop.getPrivateKey(), 24 * 60); response.addHeader("Authorization", "Bearer "+token); try { response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); PrintWriter out = response.getWriter(); Map resultMap = new HashMap(); resultMap.put("code", HttpServletResponse.SC_OK); resultMap.put("msg", "認證通過!"); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); }catch (Exception outEx){ outEx.printStackTrace(); } } }
資源伺服器,可以從token中,拿到認證資訊,在放到 SecurityContextHolder.getContext().setAuthentication(authResult);中
public class JwtVerifyFilter extends BasicAuthenticationFilter { private RsaKeyProperties prop; public JwtVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) { super(authenticationManager); this.prop = prop; } @Override public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Bearer ")) { //如果攜帶錯誤的token,則給使用者提示請登入! chain.doFilter(request, response); response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpServletResponse.SC_FORBIDDEN); PrintWriter out = response.getWriter(); Map resultMap = new HashMap(); resultMap.put("code", HttpServletResponse.SC_FORBIDDEN); resultMap.put("msg", "請登入!"); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); } else { //如果攜帶了正確格式的token要先得到token String token = header.replace("Bearer ", ""); //驗證tken是否正確 Payload<SysUser> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), SysUser.class); SysUser user = payload.getUserInfo(); if(user!=null){ UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authResult); chain.doFilter(request, response); } } } }