ホームページ  >  記事  >  Java  >  SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

王林
王林転載
2023-05-11 10:28:051454ブラウズ

準備

spring-boot: 2.1.4.RELEASE

spring-security-oauth3: 2.3.3.RELEASE (ソースコードを使用する場合は、これを変更しないでください)バージョン番号は任意、2.4以降は書き方が違うので)

mysql: 5.7

エフェクト表示

ここではテストにpostmanのみを使用しており、フロントは終了ページはまだドッキングに使用されていません。次に、バージョン ロール メニューの権限割り当てのページが表示されます。メニュー

1。オープン インターフェイス http://localhost:7000/open/hello ## にアクセスします。

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

#2 . トークンなしで、保護されたインターフェイス http://localhost:7000/admin/user/info

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

# にアクセスします。 3. ログイン後にトークンを取得し、トークンを持ってアクセスし、正常に戻る 現在のログインユーザー情報

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

realize

oauth3 には合計 4 つのモードがありますが、ここでは説明しません。はい、オンラインで検索したところ、同じことが見つかりました。

ここでは一方的なアプリケーションのみを考慮しているため、パスワード モードを使用します。

SpringCloud Oauth3、ゲートウェイ認証については後ほど記事で紹介します

いくつかのポイントについて話しましょう

1. インターセプター設定の動的権限

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

新しい MySecurityFilter クラスを作成し、AbstractSecurityInterceptor を継承し、Filter インターフェイスを実装します。

初期化、カスタム アクセス意思決定マネージャー

@PostConstruct
 public void init(){
        super.setAuthenticationManager(authenticationManager);
        super.setAccessDecisionManager(myAccessDecisionManager);
  }

カスタム フィルターはセキュリティ メタデータを呼び出しますソース

@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
    return this.mySecurityMetadataSource;
}

まず、安全なメタデータ ソースを呼び出すカスタム フィルターのコア コードを見てみましょう。

次のコードは、現在のリクエストが受信されるために必要なアクセス許可 (ロール) を取得するために使用されます

/**
     * 获得当前请求所需要的角色
     * @param object
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        String requestUrl = ((FilterInvocation) object).getRequestUrl();

        if (IS_CHANGE_SECURITY) {
            loadResourceDefine();
        }
        if (requestUrl.indexOf("?") > -1) {
            requestUrl = requestUrl.substring(0, requestUrl.indexOf("?"));
        }
        UrlPathMatcher matcher = new UrlPathMatcher();
        List<Object> list = new ArrayList<>();  //无需权限的,直接返回
        list.add("/oauth/**");
        list.add("/open/**");
        if(matcher.pathsMatchesUrl(list,requestUrl))
            return null;

        Set<String> roleNames = new HashSet();
        for (Resc resc: resources) {
            String rescUrl = resc.getResc_url();
            if (matcher.pathMatchesUrl(rescUrl, requestUrl)) {
                if(resc.getParent_resc_id() != null && resc.getParent_resc_id().intValue() == 1){   //默认权限的则只要登录了,无需权限匹配都可访问
                    roleNames = new HashSet();
                    break;
                }
                Map map = new HashMap();
                map.put("resc_id", resc.getResc_id());
                // 获取能访问该资源的所有权限(角色)
                List<RoleRescDTO> roles = roleRescMapper.findAll(map);
                for (RoleRescDTO rr : roles)
                    roleNames.add(rr.getRole_name());
            }
        }

        Set<ConfigAttribute> configAttributes = new HashSet();
        for(String roleName:roleNames)
            configAttributes.add(new SecurityConfig(roleName));

        log.debug("【所需的权限(角色)】:" + configAttributes);

        return configAttributes;
    }

カスタム アクセス デシジョン マネージャーのコア コードを見てみましょう。このコードは主に、現在ログインしているユーザー (現在ログインしているユーザーが所有するロールは最後の項目に書き込まれます) が、権限ロール

@Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){   //属于白名单的,不需要权限
            return;
        }
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while (iterator.hasNext()){
            ConfigAttribute configAttribute = iterator.next();
            String needPermission = configAttribute.getAttribute();
            for (GrantedAuthority ga: authentication.getAuthorities()) {
                if(needPermission.equals(ga.getAuthority())){   //有权限,可访问
                    return;
                }
            }
        }
        throw new AccessDeniedException("没有权限访问");

    }

2. 共通の結果を返すように認証例外をカスタマイズする

なぜこれが必要なのでしょうか? これが構成されていない場合、フロントエンドとバックエンドが権限を理解することが困難になります。認証失敗によって返されたコンテンツ. それはまだ不可能です. 統一された解釈, これ以上の苦労はせずに、まず設定なしで返される状況と設定を見てみましょう

(1) カスタマイズの前に、保護された API インターフェイスにアクセスする場合

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

# (2) 認証に失敗したインターフェースがインターフェースに戻った後、次のようになると規定します。処理してユーザーにプロンプ​​トを表示するほうがよいでしょうか

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

わかりました、どこを設定するかを見てみましょう

リソース サーバー OautyResourceConfig を書き換えます認証をカスタマイズするためのコードの次の部分 例外によって返された結果

これを参照できます https://www.yisu.com/article/131668.htm

@Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(authenticationEntryPoint)    //token失效或没携带token时
                .accessDeniedHandler(requestAccessDeniedHandler);   //权限不足时
    }

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?#3. 現在のログイン ユーザーを取得します

##最初の方法: JWT を使用してユーザー情報を伝え、トークンを取得した後に解析します

##今のところ説明はありません

2 番目の方法: UserDetails インターフェイスを実装する SecurityUser を作成します (これがこのプロジェクトで使用されます)

元の唯一の UserDetails インターフェイスにはユーザー名とパスワードしかありません。ここでシステムにユーザーを追加します。

protected User user;
    public SecurityUser(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

BaseControllerでは、各Controllerがこれを継承してgetUser()メソッドを記述し、ユーザーがトークンを持ってアクセスすれば、現在ログインしているユーザーの情報を直接取得することができます。

protected User getUser() {
        try {
            SecurityUser userDetails = (SecurityUser) SecurityContextHolder.getContext().getAuthentication()
                    .getPrincipal();

            User user = userDetails.getUser();
            log.debug("【用户:】:" + user);

            return user;
        } catch (Exception e) {
        }
        return null;
    }

ユーザーが正常にログインした後、ユーザーのロール コレクションなどを取得する方法については、ここで UserDetailsS​​ervice インターフェイスを実装する必要があります

@Service
public class TokenUserDetailsService implements UserDetailsService{

    @Autowired
    private LoginService loginService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = loginService.loadUserByUsername(username);  //这个我们拎出来处理
        if(Objects.isNull(user))
            throw new UsernameNotFoundException("用户名不存在");
        return new SecurityUser(user);
    }
}

次に、セキュリティ構成クラスの UserDetailsS​​ervice を上で書いたものに設定します

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

最後に、loginService にメソッドを実装し、それに基づいてユーザーが存在するかどうかを判断するだけです。実際の業務処理など。

@Override
    public User loadUserByUsername(String username){
        log.debug(username);
        Map map = new HashMap();
        map.put("username",username);
        map.put("is_deleted",-1);
        User user = userMapper.findByUsername(map);
        if(user != null){
            map = new HashMap();
            map.put("user_id",user.getUser_id());
            //查询用户的角色
            List<UserRoleDTO> userRoles = userRoleMapper.findAll(map);
            user.setRoles(listRoles(userRoles));
            //权限集合
            Collection<? extends GrantedAuthority> authorities = merge(userRoles);
            user.setAuthorities(authorities);
            return user;
        }
        return null;

    }
SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?データベースファイルはこの中にあります

SpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?

以上がSpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。