shiro簡易Javaセキュリティフレームワーク


この2,3日はプロジェクトでシロというフレームワークが使われていたので、休みの間にシロをしっかり補習していました.
一、シロって何?
shiroは強力なJavaセキュリティフレームワークであり、認証を実行します.ライセンス、パスワード、セッション管理.shiroを使用するとAPIが分かりやすく、どのアプリケーションにも簡単に統合できます.
ここでも説明します:Spring Securityというセキュリティフレームワークについては、両者は機能的に非常に似ているので、一つを勉強した後、最後にもう一つを勉強したほうがいいです.
二、shiroの三大コアコンポーネント
1、subject:現在の操作ユーザーを表すと簡単に理解できます.実はその深層表現の意味は第三者のプロセスです.これは、現在のシステムとインタラクティブな「もの」を意味します.ここでは、私たちのシステムを直接操作しているので、一般的には、subjectは現在のユーザーであり、subjectを通じてログイン認証が必要なユーザー名パスワードが安全な操作データに関連していることを簡単に取得することができます.
2、securityManager:shiroフレームワークの核心であり、典型的なFacadeモードであり、shiroはSecurityManagerによって内部コンポーネントインスタンスを管理し、それによって安全管理の各種サービスを提供する.
3、Realm:Realmはshiroフレームワークとアプリケーションセキュリティデータとの架け橋またはコネクタであり、ユーザーが認証/認可を登録する必要がある場合、shiroはアプリケーション構成のRealmからユーザーとその権限情報を検索する.
ここで注意すべきことは、shiroを構成する際に、少なくとも1つのRealmを指定する必要があります.ユーザー認証または認可は、複数のRealmを構成することができます.
三、SpringBoot集積Shiro
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
</dependency>

プロジェクトでは、shiroコンフィギュレーションクラスを構成するのが一般的です.このクラスでは、shiroで非常に重要な認証、アクセス制御情報、およびRealmの管理を構成します.
私が書いたshiroConfigの例を書いてみます.参考にしてください.
/**
 * 2020/05/20
 */
@Configuration
public class ShiroConfig {
    //  Shiro      
    @Bean
    public SecurityManager securityManager(Realm myRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //    Realm,  Realm                       
        securityManager.setRealm(myRealm);
        return securityManager;
    }
    //        Realm bean,       bean                
    @Bean
    public Realm myRealm(){
        MyRealm realm=new MyRealm();
        return realm;
    }

    //    Shiro    bean,  bean   Shiro          
    //                         
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        //  Shiro        ,           
        ShiroFilterFactoryBean shiroFilter=new ShiroFilterFactoryBean();
        //  Shiro     ,             Realm           
        shiroFilter.setSecurityManager(securityManager);
        //             ,         html jsp     ,            
        //       Shiro                 , Shiro                          
        //        
        shiroFilter.setLoginUrl("/");
                //         ,             Shiro  ,       Shiro             
        shiroFilter.setSuccessUrl("/success");
        //           ,            Shiro               ,  Shiro     
        //       ,            
        shiroFilter.setUnauthorizedUrl("/noPermission");
        //    Map  ,  Map              ,      Shiro                     
        Map<String,String> map=new LinkedHashMap<String,String>();
        //  /login              anon               (         )
        map.put("/login","anon");
       //                                  
        //         Shiro   
        //  /admin/**             ,  admin               
        //  authc             (  ),    (  )      
        //   : **         
        //       *           
        //       ?           
        map.put("/admin/**","authc");
        map.put("/user/**","authc");
        //                   ,        Map      ,        
        //      /**                   Shiro       
//        map.put("/**","authc");
        shiroFilter.setFilterChainDefinitionMap(map);
        return shiroFilter;
    }
}

簡単なログインURL、ログイン成功URL、nopermission権限のないURLが配置されています.そしてMyRealmオブジェクトはspringによって管理されます.後ろにブロック機能に似た/admin/**があります....認証が必要なのか、認証が必要なのか、対応する役割、権限などが必要なのか.
MyRealm:
/**
 * 2020/05/20
 */
public class MyRealm extends AuthorizingRealm  {

    /**
     *                   , Shiro     
     * @param authenticationToken                    
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username=token.getUsername();//            
        String password=new String(token.getPassword());//                      
        System.out.println(username+" -----  "+password);

        /**
         *     ,             ,
         *     if            
         */
        if(!"admin".equals(username)&&!"zhangsan".equals(username)&&!"user".equals(username)){
            throw new UnknownAccountException();//         
        }

        /**
         *     ,                        ,          
         * IP      ,               
         */
        if("zhangsan".equals(username)){
            throw new LockedAccountException();//        
        }
        /**
         *                                     ,                  
         *   :
         *                   ,               ,             
         *                                      
         */
        //                   
//        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
//        credentialsMatcher.setHashAlgorithmName("MD5");
//        credentialsMatcher.setHashIterations(2);
//
//        this.setCredentialsMatcher(credentialsMatcher);

        //            
//        Object obj = new SimpleHash("MD5","123456","",1);
        return new SimpleAuthenticationInfo(username,"e10adc3949ba59abbe56e057f20f883e",getName());
    }

    /**
     *        ,                                  
     *                        ,    shiro 
     *   :              ,Shiro        ,                  
     *                                   
     * @param principalCollection
     * @return
     */

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //       ,              
        Object obj = principalCollection.getPrimaryPrincipal();
        //       set             
        Set<String> roles = new HashSet<>();
        if("admin".equals(obj)){
            System.out.println(" ---     admin --------");
            roles.add("admin");
            roles.add("user");
        }
        if("user".equals(obj)){
            System.out.println(" ---     user --------" + obj);
            roles.add("user");
        }
        Set<String> permissions = new HashSet<>();
        if("admin".equals(obj)){
            //      admin:add           admin  add  
            permissions.add("admin:add");
        }
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();

        info.setRoles(roles);
        info.setStringPermissions(permissions);

        return info;
    }

その最も基本的なRealmクラスが作成され、1、doGetAuthenticationInfo shiroがユーザー認証時に自動的にこのメソッドを呼び出す2つの方法が表示されます.この方法のパラメータは,実際には簡易なユーザアイデンティティトークンを用いていることがわかる.このユーザは当然認証が必要なユーザであり,トークンから現在の認証ユーザのユーザ名とログインパスワードを取り出すことができる.自然の後ろにはMD 5などのパスワード暗号化があります.ユーザのアイデンティティを最終的に判断するには、何回の塩添加反復が必要であるか.
2.doGetAuthorizationInfoが許可したコールバック方法.この方法には、現在のユーザーに権限を与える操作が含まれていることがわかります.
あちらはみんなのテストを便利にしてcontrollerを書きました.
/**
 * 2020/05/20
 */

@Controller
public class TestController {

    @RequestMapping("/")
    public String index(){
        return "login";
    }

    @RequestMapping("/login")
    public  String login(String username, String password, Model model){
        //        ,             
        Subject subject= SecurityUtils.getSubject();
        //  ,                    ,        ,  Shiro          
        //  :                      
        subject.logout();
        //       (     ),  if               
        if(!subject.isAuthenticated()){
            //            ,                   
            UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
            try {

                /**
                 *     ,       Realm        
                 *              
                 */
                subject.login(usernamePasswordToken);
            } catch (UnknownAccountException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","    !");
                return "login";
            }catch (LockedAccountException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","     !");
                return "login";
            }catch (IncorrectCredentialsException e) {
//                e.printStackTrace();
                model.addAttribute("errorMessage","    ");
                return "login";
            }catch (AuthenticationException e) {
                e.printStackTrace();
                model.addAttribute("errorMessage","    !");
                return "login";
            }
        }

        return "redirect:/success";
    }

    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        //      shiro   ,        
        subject.logout();
        return "redirect:/";
    }

    @RequestMapping("/success")
    public String loginSuccess(){
        return "success";
    }
    @RequestMapping("/noPermission")
    public String noPermission(){
        return "noPermission";
    }


    @RequiresRoles(value = {"admin"})
    @RequestMapping("/admin/test")
    public @ResponseBody
    String adminTest(){
        return "/admin/test  ";
    }

    /**
     *            ,            
     * @return
     */
    @RequiresAuthentication
    @RequestMapping("/admin/test01")
    public @ResponseBody String adminTest01(){
        return "/admin/test01  ";
    }
    /**
     * @RequiresPermissions                         RequiresRoles  
     */
    @RequiresPermissions(value={"admin:add"})
    @RequestMapping("/admin/add")
    public @ResponseBody String adminAdd(){
        return "/admin/add  ";
    }

    @RequiresRoles(value = {"user"})
    @RequestMapping("/user/test")
    public @ResponseBody String userTest(){
        return "/user/test  ";
    }

    /**
     *               authorizationException  shiroException
     */
    @ExceptionHandler(value={AuthorizationException.class})
    public String permissionError(Throwable throwable){
        //            ,      throwable           
        //                          ,                 
        //    
        return "noPermission";
    }
}

login.htmlログインページ
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script th:src="@{|/js/jquery-1.11.3.min.js|}"></script>
    <script th:src="@{|/js/jQuery.md5.js|}"></script>
    <script>
        $(function(){
            $("#loginBut").bind("click",function(){
                var v_md5password=$.md5($("#password").val());
                $("#md5Password").val(v_md5password)
            })
        })
    </script>
</head>
<body>
<form action="login" method="post">
      <input type="text" name="username"><br>
      <input type="text"  id="password"><br>
    <input type="hidden" name="password" id="md5Password">
    <input type="submit" value="  " id="loginBut">
</form>

<span style="color: red" th:text="${errorMessage}"></span>

</body>
</html>

noPermission.html権限ページなし
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>   !       !</h1>
</body>
</html>

success.htmlログイン成功ページ
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--     shiro  -->
<h1 shiro:guest="true">      </h1>
<!--     -->
<shiro:authenticated>
    <h1>    </h1><br>
</shiro:authenticated>

<a href="/logout">  </a><br><br><br>

<a th:href="@{|/admin/test|}">   admin     </a><br>
<a th:href="@{|/admin/test01|}">   admin     test01</a><br>
<a th:href="@{|/admin/add|}">   admin     add</a><br>
<a th:href="@{|/user/test|}">   user     </a><br>
</body>
</html>

このような最も簡単なshiroプロジェクトは構築に成功したが、開発中にshiroフレームワークはこのように使用されないと言いたい.特に、特定のURLに特定のロールと権限が必要な場合、プロファイルに大量に構成され、プロジェクトのメンテナンスコストが増加します.後期URLアドレスは特に多く、私たちのshiroConfigという構成クラスは非常に膨大になる可能性があります.そこで次の一枚はshiroの注釈ベースの開発とよくあるshiroラベル(shiro統合thymeleafの使い方)についてお話ししたいと思います.
–未完待機
OK、週末は楽しかった~