How does springcloud do permission management (springsecurity)

How does springcloud do permission management (springsecurity + auth2)?

First look at a vein diagram:
Insert picture description here
now, step by step:

Step 1: Configure the zuul gateway

Bring the request header in the zuul gateway without interception

@Component
@Slf4j
public class AuthFilter extends ZuulFilter {

	/**
     * 具体的过滤逻辑
     * 本例中,检查请求的参数中是否传了token这个参数,如果没传,则请求不被路由到具体的服务实例,
     * 直接返回响应,状态码为401
     * @return
     */
	@Override
	public Object run() {
		//过滤器过滤
		System.out.println("………preHandle……………");

		RequestContext requestContext = RequestContext.getCurrentContext();
		HttpServletRequest request = requestContext.getRequest();
		String header = request.getHeader("Authorization");
		if (null != header && !"".equals(header)) {
			requestContext.addZuulRequestHeader("header", header);

		}
		return null;
	}

	 /**
     * 表示该过滤器是否过滤逻辑,如果是ture,则执行run()方法;如果是false,则不执行run()方法.
     * @return
     */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
     * 过滤顺序,值越小,越早执行该过滤器
     * @return
     */
	@Override
	public int filterOrder() {
		// 过滤的顺序
		return 0;
	}

	/**
     * Zuul有一下四种过滤器
     * "pre":是在请求路由到具体的服务之前执行,这种类型的过滤器可以做安全校验,例如身份校验,参数校验等
     * "routing":它用于将请`在这里插入代码片`求路由到具体的微服务实例,在默认情况下,它使用Http Client进行网络请求
     * "post":它是在请求已被路由到微服务后执行,一般情况下,用作收集统计信息,指标,以及将响应传输到客户端
     * "error":它是在其他过滤器发生错误时执行
     */
	@Override
	public String filterType() {
		return "pre";
	}

}

Note: requestContext.addZuulRequestHeader (“header”, header); This sentence needs to avoid sensitive words, such as Authorization, etc.

Step 2: Configure specific microservices (both microservices are similar, here is an example)

①Guide package:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

② Write a class WebSecurityConfig to release all requests, because all requests are not passed after the package is imported.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                authorizeRequests().
                antMatchers("/**").
                permitAll().
                anyRequest().
                authenticated().
                and().
                csrf().
                disable();

    }
}

③ Write the interceptor configuration class, let go of some unwanted interceptions:

@Configuration
@EnableWebSecurity
public class InterceptorConfig extends WebMvcConfigurationSupport {
    @Autowired
    private JwtInterceptor jwtInterceptor;
    protected void addInterceptors(InterceptorRegistry registry) {
        //注册拦截器要声明拦截器对象和要拦截的请求
        System.out.println("进入InterceptorConfig类的addInterceptors方法!");
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**").
                excludePathPatterns("/**/login/**").
                excludePathPatterns("/**/regist/**").
                excludePathPatterns("/**/captcha/**");
    }
}

④ Configure interceptors to do real core interception content

@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtUtil jwtUtil;
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("………preHandle……………");
        //拦截器只是负责把头请求头中包含token的令牌进行一个解析验证。
        if (null == request ||
                null == request.getHeader("header") ||
                !request.getHeader("header").startsWith("Bearer ")) {
            outPutErrorResult(response);
            return false;

        }
        String token = request.getHeader("header").substring(7);
        System.out.println("token:" + token);
        if (StringUtils.isEmpty(token)) {
            outPutErrorResult(response);
            return false;
        }
        try {
            Claims claims = jwtUtil.parseJwt(token);
        } catch (Exception e) {
            e.printStackTrace();
            outPutErrorResult(response);
            return false;
        }

        return true;
    }

    public void outPutErrorResult(HttpServletResponse response) {
        ServletOutputStream output = null;
        try {
            output = response.getOutputStream();
            output.write(("{\"status\":\"error\",\"msg\":\"请登录账号@!\",\"code\":\"500\"}").getBytes());
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

It should be pointed out here that
Claims claims = jwtUtil.parseJwt (token); The
reason why the token can be judged in this way is because the token generation method here is generated using the jjwt method, so it can be parsed in this way.
See the token generation method:
guide package:

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
  public String createJWT(String id, String subject, String roles) {
        long nowMinius = System.currentTimeMillis();
        JwtBuilder builder = Jwts.
                builder().setId(id).
                setSubject(subject).
                setIssuedAt(new Date()).
                signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
        if (ttl > 0) {
            builder.setExpiration(new Date(nowMinius + ttl));
        }
        return builder.compact();
    }

    public void setTtl(long ttl) {
        this.ttl = ttl;
    }

    /**
     * 解析JWT
     *
     * @param jwtStr
     * @return
     */
    public Claims parseJwt(String jwtStr) {
        return Jwts.parser().setSigningKey(key).parseClaimsJws(jwtStr).getBody();
    }
Step 3: Write a class SecuringRequestInterceptor, bring the request header when the microservices call each other, or they will be intercepted (each business microservice must be written).
@Component
public class SecuringRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ////获取上一个请求保存的RequestAttributes,能获取到当前的HttpServletRequest
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        //获取request域
        HttpServletRequest request = attributes.getRequest();
        //获取头部信息
        Enumeration<String> headerNames = request.getHeaderNames();
        //把头部信息里面的信息装进去requestTemplate
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                System.out.println("name:"+name);
                String values = request.getHeader(name);
                System.out.println("values:"+values);
                requestTemplate.header(name, values);
            }
        }
    }
}

There is basically no problem here,

The fourth step is to write an abstract class AbstractController.java to facilitate other classes to use the user name user id user role and other content. (not necessary)
 @Autowired
    protected HttpServletRequest request;
    @Autowired
    private JwtUtil jwtUtil;
    
public abstract class AbstractController {

    @Autowired
    protected HttpServletRequest request;
    @Autowired
    private JwtUtil jwtUtil;

    public SysLogUserVo UserInfo(){
        SysLogUserVo svuv = new SysLogUserVo();
        String header = request.getHeader("header");
        String token = header.substring(7);
        try {
            Claims claims = jwtUtil.parseJwt(token);
            svuv.setAccounts(claims.getSubject());
            svuv.setId(Integer.parseInt(claims.getId()));
            svuv.setRole_name((String) claims.get("roles"));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return svuv;
    }
}

Other classes want to obtain user information only need to inherit this class

Published 67 original articles · Liked12 · Visitors 10,000+

Guess you like

Origin blog.csdn.net/m0_37635053/article/details/103563571