Springcloudはどのように権限管理を行いますか(SpringSecurity)

springcloudはどのように権限管理(springsecurity + auth2)を行いますか?

まず、静脈図を見てください。
ここに画像の説明を挿入
今、ステップバイステップ:

ステップ1:zuulゲートウェイを構成する

インターセプトせずにリクエストヘッダーをzuulゲートウェイに持ってくる

@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";
	}

}

注:requestContext.addZuulRequestHeader(“ header”、header);この文は、Authorizationなどのデリケートな単語を避ける必要があります。

ステップ2:特定のマイクロサービスを構成します(両方のマイクロサービスは類似しています。ここに例を示します)

①ガイドパッケージ:

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

②すべてのリクエストはパッケージのインポート後に渡されないため、クラスWebSecurityConfigを作成してすべてのリクエストを解放します。

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

    }
}

③インターセプター構成クラスを記述し、いくつかの不要なインターセプトを手放します。

@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/**");
    }
}

④実際のコア傍受コンテンツを実行するようにインターセプターを構成する

@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();
                }
            }
        }
    }
}

ここで、
Claims Claims = jwtUtil.parseJwt(token)であることを指摘しておく必要があります。トークン
をこのように判断できるのは、ここでのトークン生成メソッドがjjwtメソッドを使用して生成されるため、この方法で解析できるためです。
トークン生成方法を参照してください:
ガイドパッケージ:

<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();
    }
ステップ3:SecuringRequestInterceptorクラスを作成し、マイクロサービスが相互に呼び出したときにリクエストヘッダーを取得します。そうしないと、インターセプトされます(各ビジネスマイクロサービスを作成する必要があります)。
@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);
            }
        }
    }
}

ここでは基本的に問題はありませんが、

4番目のステップは、抽象クラスAbstractController.javaを記述して、他のクラスがユーザー名、ユーザーID、ユーザーロール、およびその他のコンテンツを使用できるようにすることです。(オプション)
 @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;
    }
}

他のクラスはユーザー情報を取得したいだけで、このクラスを継承する必要があります

67件の元の記事を公開 いいね12 10,000人以上の訪問者

おすすめ

転載: blog.csdn.net/m0_37635053/article/details/103563571