本例子 包含有 一下模块: 

eureka 模块,充当 注册中心角色

user-service-api 客户端接口和实体

user-service-provider 客户端服务提供者

user-conusmer 客户端消费者

zuul 模块为网关,用来实现统一路由与 存放 前端静态资源

security-config   spring security客户公共的实现

 

 

认证逻辑的实现:

 

首先 zuul 模块下 的 login.html  登录页面 输入用户名密码后,点击 登录 后就会触发 一下代码

 $("#loginBtn").click(function(){

          $.ajax({
              url:"/user-consumer/login",
              type:"POST",
              dataType:"json",
              async:false,
              contentType:"application/json;charset=utf-8",
              data: JSON.stringify({userName:$("#userName").val(),password:$("#password").val(),}),
              success:function(message){
                  console.log(".....................");
                  console.log(message=="ok");
                  console.log(message);
                  if(message.result=="ok"){
                      console.log(message);
                      window.location.href="/main.html";
                  }else{
                      console.log(message);
                  }
              },
              error:function(message){
                  console.log(".....................");
                  console.log(message);;
              }
          });


		  
	  });

点击登录 按钮,就会 由zuul 网关,路由到 user-consumer服务的 /login , 当 请求 路由到 user-consumer时 就会被 

spring security 的  JwtUsernamePasswordAuthenticationFilter 过滤器拦截,此时就会执行如下代码

 @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse rsp)
            throws AuthenticationException {
        try {
            User user = new ObjectMapper().readValue(req.getInputStream(),User.class);
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            user.getUserName(),
                            user.getPassword(),
                            new ArrayList<>())
            );
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

把用户名 和 密码 保证成 token , 供 自定义 的 provider 使用,下面是 自定义 provider 的核心代码

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String name = authentication.getName();
        String password = authentication.getCredentials().toString();

        UserDetails userDetails = userDetailsService.loadUserByUsername(name);
        if(userDetails!=null){
            if(bCryptPasswordEncoder.matches(password,userDetails.getPassword())){
                Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
                Authentication auth = new UsernamePasswordAuthenticationToken(name,password,authorities);
                return auth;
            }
        }

        return null;
    }

自定义 的 provider 将 认证 用户的 凭证,认证 成功 后 将 执行  JwtUsernamePasswordAuthenticationFilter的

successfulAuthentication 生成 token,返回给浏览器,以后浏览器每次请求都要携带该token,

一下 是 successfulAuthentication 的代码

 @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse rsp, FilterChain chain,
                                            Authentication auth) {

        Map<String,Object> map = new HashMap<>();
        map.put("username",auth.getName());
        map.put("authorities",auth.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority).collect(Collectors.toList()));

        String token = JwtTokenUtils.generatorToken(map);


        rsp.addHeader("Set-Cookie",
                "access_token="+token+";Path=/;HttpOnly");
        try {
            rsp.getWriter().write("{\"result\":\"ok\"}");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

 

 

每次 请求 都需要经过 JwtTokenAuthenticationFilter 过滤器,对token 进行解析

一下是 JwtTokenAuthenticationFilter 的核心代码

@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String token= CookieUtil.getCookieValue(request,ACCESS_TOKEN);
        if(token!=null){

            try{
                Claims claims= JwtTokenUtils.phaseToken(token);
                String username = claims.get("username").toString();
                List<String> authorities = claims.get("authorities", List.class);
                if (username != null) {
                    UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null,
                            authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
           
            }catch (Exception e){
                response.setContentType("text/html;charset=UTF-8");
                response.getWriter().write("{\"code\":\"-1\",\"msg\":\"error\"}");
            }

        }

        filterChain.doFilter(request, response);
    }

 

代码 例子 https://gitee.com/shenduedu/base_spring_cloud.git

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐