1. 程式人生 > >Spring Boot實現OAuth 2.0(二)-- 自定義許可權驗證

Spring Boot實現OAuth 2.0(二)-- 自定義許可權驗證

自定義攔截器進行許可權驗證

涉及到的姿勢:

  • 自定義註解
  • 攔截器
  • Spring Boot新增攔截器

文章目錄:

自定義註解

@Target(ElementType.METHOD)//作用在方法
@Retention(RetentionPolicy.RUNTIME)//僅在執行時
@Documented
public @interface RoleAnnotation {

    /**
     * <b>“且”關係的Role</b>
     * <p>必須指定type</p>
     */
    public static String TYPE_AND = "and"
; /** * <b>“或”關係的Role</b> */ public static String TYPE_OR = "or"; /** * <b>“混合”關係的Role</b> * <p>必須指定type</p> */ public static String TYPE_MIXED = "mixed"; /** * <b>Role之間的關聯方式</b> */
String type() default RoleAnnotation.TYPE_OR; /** * <b>“且”關係的Role</b> * <p>必須指定type</p> */ String[] and() default {}; /** * <b>“或”關係的Role</b> */ @AliasFor("value") String[] or() default {}; @AliasFor
("or") String[] value() default {}; /** * <b>“混合”關係的Role</b> * <p>必須指定type</p> */ String mixed() default ""; // ( (hr && fe) || admin ) }

在這裡定義的是自定義註解,只相當於介面,還沒有實現。
在下面的攔截器中,會出現自定義註解的實現。
在這裡提兩個姿勢點:

  1. @AliasFor(“or”)是取別名,這樣就可以讓使用註解人,使用自己喜歡的註解關鍵字。
  2. value()方法是註解的預設方法,給value賦值的時候,@RoleAnnotation(value = “”) 可以直接寫成@RoleAnnotation( “”)。再加上@AliasFor的作用,你就可以讓自定義註解,將預設值賦值給你想要的那個欄位。

自定義攔截器

@Service("qiYunRoleInterceptor")
public class RoleInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenStore tokenStore;

    @Override
    public boolean preHandle(
    HttpServletRequest request,
    HttpServletResponse response,
    Object handler)
            throws Exception {
        HandlerMethod handlerMethod =(HandlerMethod) handler;
        RoleAnnotation roleAnnotation = 
                handlerMethod.getMethodAnnotation(RoleAnnotation.class);// 在這裡使用了自定義註解,也就相當於註解的實現類
        if (roleAnnotation == null) {
            return true;
        }

        String token = request.getParameter("access_token");
        if (StringUtils.isEmpty(token)) {
            noPermission(response);
            return false;
        }
        OAuth2Authentication auth = tokenStore.readAuthentication(token);
        Collection<GrantedAuthority> authorities = auth.getAuthorities();
        if (authorities.isEmpty()) {
            noPermission(response);
            return false;
        }

        Set<String> permissons = new HashSet<String>();
        for (GrantedAuthority authority : authorities) {
            permissons.add(authority.getAuthority());
        }

        boolean hasRole = false;
        String dealType = roleAnnotation.type();
        switch (dealType) {
            case RoleAnnotation.TYPE_OR :
                String[] orRoles = roleAnnotation.or();
                for (String orRole : orRoles) {
                    if (permissons.contains(orRole)) {
                        hasRole = true;
                        break;
                    }
                };
                break;
            case RoleAnnotation.TYPE_AND :
                String[] andRoles = roleAnnotation.and();
                Set<String> requireRoles = new HashSet<String>();
                for (String role : andRoles) {
                    requireRoles.add(role);
                }
                if (permissons.containsAll(requireRoles)) {
                    hasRole = true;
                }
                break;
            case RoleAnnotation.TYPE_MIXED :
                break;
        }

        if (!hasRole) {
            noPermission(response);
        }
        return hasRole;
    }

    private void noPermission(HttpServletResponse response) throws IOException {
        response.setContentType("application/json; charset=utf-8");  
        response.setCharacterEncoding("UTF-8");  

        JSONObject json = new JSONObject();
        json.put("error code", "500");
        json.put("description", "no permission");

        String error = json.toString();
        OutputStream out = response.getOutputStream();  
        out.write(error.getBytes("UTF-8"));  
        out.flush();  
        out.close();
    }

}

配置WebMvcConfigurer

@Configuration
public class MvcConfigurer implements WebMvcConfigurer {

    @Autowired
    @Qualifier("qiYunRoleInterceptor")
    private HandlerInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(interceptor).addPathPatterns("/api/**");
    }

}