Shiro custom encryption, authorization, caching, session management and logout

1. Summary and plan

1.1 Summary

  • SpringBoot integrates Shiro to complete authority management

  • Shiro function

  •  
     
    • Certification

    • Authorization

  • SpringBoot project deployment

    • jar包

    • nohup java -jar *.jar

  • layui use

1.2 Plan

  • shiro

    • Encryption (authentication)

    • Authorization

      • filter

      • annotation

      • java code

      • HTML(√)

    • Cache management

    • session management

    • RememberMe

    • Multi-Realm configuration

Two, encryption

  • Plain text ----- (encryption rules) ----- cipher text

  • Encryption rules can be customized, we usually use BASE64 and MD5 encoding in project development

    • BASE64: Reversible encoding method (symmetric)

      • Plaintext-ciphertext

      • Ciphertext-plaintext

    • MD5: Irreversible encoding method (asymmetric)

      • Plaintext-ciphertext

  • If the password of the database user is stored in ciphertext, how does Shiro complete the verification?

  • Use the encryption function provided by Shiro to encrypt the entered password before authentication.

2.1 Introduction to encryption

 
 

2.2 Shiro uses encryption authentication

  • Configure matcher

    @Configuration
    public class ShiroConfig {
    ​
        //...
        @Bean
        public HashedCredentialsMatcher getHashedCredentialsMatcher(){
            HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
            //matcher就是用来指定加密规则
            //加密方式
            matcher.setHashAlgorithmName("md5");
            //hash次数
            matcher.setHashIterations(1);   //此处的循环次数要与用户注册是密码加密次数一致
            return matcher;
        }
    ​
        //自定义Realm
        @Bean
        public MyRealm getMyRealm( HashedCredentialsMatcher matcher ){
            MyRealm myRealm = new MyRealm();
            myRealm.setCredentialsMatcher(matcher);
            return myRealm;
        }
    ​
        //...
    }
    ​

2.3 User registration password encryption processing

  • registh.html

    <form action="/user/regist" method="post">
        <p>帐号:<input type="text" name="userName"/></p>
        <p>密码:<input type="text" name="userPwd"/></p>
        <p><input type="submit" value="提交注册"/></p>
    </form>
  • UserController

    @Controller
    @RequestMapping("user")
    public class UserController {
    ​
        @Resource
        private UserServiceImpl userService;
    ​
    ​
    ​
        @RequestMapping("/regist")
        public String regist(String userName,String userPwd) {
            System.out.println("------注册");
    ​
            //注册的时候要对密码进行加密存储
            Md5Hash md5Hash = new Md5Hash(userPwd);
            System.out.println("--->>>"+ md5Hash.toHex());
    ​
            //加盐加密
            int num = new Random().nextInt(90000)+10000;   //10000—99999
            String salt = num+"";
            Md5Hash md5Hash2 = new Md5Hash(userPwd,salt);
            System.out.println("--->>>"+md5Hash2);
    ​
            //加盐加密+多次hash
            Md5Hash md5Hash3 = new Md5Hash(userPwd,salt,3);
            System.out.println("--->>>"+md5Hash3);
    ​
            //SimpleHash hash = new SimpleHash("md5",userPwd,num,3);
            
            //将用户信息保存到数据库时,保存加密后的密码,如果生成的随机盐,盐也要保存
            
            return "login";
        }
    ​
    }

2.4 If the password is salted, Realm needs to return the salt when returning the authentication data

  • In the custom Realm:

    public class MyRealm extends AuthorizingRealm {
        
        @Resource
        private UserDAO userDAO;
        @Resource
        private RoleDAO roleDAO;
        @Resource
        private PermissionDAO permissionDAO;
    ​
        public String getName() {
            return "myRealm";
        }
    ​
        /**
         * 获取认证的安全数据(从数据库查询的用户的正确数据)
         */
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //参数authenticationToken就是传递的  subject.login(token)
            // 从token中获取用户名
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            String username = token.getUsername();
            //根据用户名,从数据库查询当前用户的安全数据
            User user = userDAO.queryUserByUsername(username);
    ​
    //        AuthenticationInfo info = new SimpleAuthenticationInfo(
    //                username,           //当前用户用户名
    //                user.getUserPwd(),   //从数据库查询出来的安全密码
    //                getName());
    ​
            //如果数据库中用户的密码是加了盐的
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    username,           //当前用户用户名
                    user.getUserPwd(),   //从数据库查询出来的安全密码
                    ByteSource.Util.bytes(user.getPwdSalt()),
                    getName());
    ​
            return info;
        }
    }

Three, log out

  • Configure in Shiro filter, configure the path corresponding to logut

    filterMap.put("/exit","logout");
  • On the "Exit" button on the page, jump to the url corresponding to logout

    <a href="exit">退出</a>

Four, authorization

After the user logs in successfully, the corresponding operation needs to have the corresponding authority; the authority is checked before the operation-authorization

There are usually two types of permissions control:

  • Users with different identities log in, and we now have different operation menus (the menu without permission is not realistic)

  • Display all menus for all users. When the user clicks on the menu, verify whether the current user has this permission. If not, it will prompt insufficient permission

4.1 HTML authorization

  • Only display the menus that the current user has permission to operate on the menu page

  • shiro standard

    <shiro:hasPermission name="sys:c:save">
        <dd><a href="javascript:;">入库</a></dd>
    </shiro:hasPermission>

4.2 Filter authorization

  • Set the permissions of the requested URL in the shiro filter

    filterMap.put("/c_add.html","perms[sys:c:save]");
    ​
    //设置未授权访问的页面路径—当权限不足时显示此页面
    filter.setUnauthorizedUrl("/lesspermission.html");

4.3 Annotation authorization

  • Configure Spring's support for Shiro annotations: ShiroConfig.java

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        autoProxyCreator.setProxyTargetClass(true);
        return autoProxyCreator;
    }
    ​
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
  • Add permission annotations to the requested controller

    @Controller
    @RequestMapping("customer")
    public class CustomerController {
    ​
        @RequestMapping("list")
        //如果没有 sys:k:find 权限,则不允许执行此方法
        @RequiresPermissions("sys:k:find")
        //    @RequiresRoles("")
        public String list(){
            System.out.println("----------->查询客户信息");
            return "customer_list";
        }
    ​
    }
  • Through global exception handling, specify page jumps when permissions are insufficient

    @ControllerAdvice
    public class GlobalExceptionHandler {
    ​
        @ExceptionHandler
        public String doException(Exception e){
            if(e instanceof AuthorizationException){
                return  "lesspermission";
            }
            return null;
        }
    ​
    }

4.4 Manual authorization

  • Manual permission verification in the code

    Subject subject = SecurityUtils.getSubject();
    if(subject.isPermitted("sys:k:find")){
        System.out.println("----------->查询客户信息");
        return "customer_list";
    }else{
        return "lesspermission";
    }

Five, cache usage

In the process of using Shiro for authorization management, each authorization will access the doGetAuthorizationInfo method in the realm to query the current user's role and authorization information. If the system has a large number of users, it will cause greater pressure on the database

Shiro supports caching to reduce the access pressure to the database (the cached is authorization information)

5.1 Import dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
​
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
​
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.4.0</version>
</dependency>

5.2 Configure caching strategy

  • Create an xml file (ehcache.xml) in the resources directory

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
​
    <diskStore path="C:\TEMP" />
​
    <cache name="users"  timeToLiveSeconds="300"  maxEntriesLocalHeap="1000"/>
​
    <defaultCache name="defaultCache"
                  maxElementsInMemory="10000"
                  eternal="false"
                  timeToIdleSeconds="120"
                  timeToLiveSeconds="120"
                  overflowToDisk="false"
                  maxElementsOnDisk="100000"
                  diskPersistent="false"
                  diskExpiryThreadIntervalSeconds="120"
                  memoryStoreEvictionPolicy="LRU"/>
            <!--缓存淘汰策略:当缓存空间比较紧张时,我们要存储新的数据进来,就必然要删除一些老的数据
                LRU 最近最少使用
                FIFO 先进先出
                LFU  最少使用
            -->
</ehcache>

5.3 Join cache management

  • ShiroConfig.java

@Bean
public EhCacheManager getEhCacheManager(){
    EhCacheManager ehCacheManager = new EhCacheManager();
    ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
    return ehCacheManager;
}
​
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(myRealm);
    securityManager.setCacheManager(getEhCacheManager());
    return securityManager;
}

Six, session management

Shiro's authentication and authorization are based on the session. Shiro includes session management

  • If we need to manage the session

    • Custom session manager

    • Set a custom session manager to SecurityManager

  • Configure custom SessionManager: ShiroConfig.java

    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        System.out.println("----------"+sessionManager.getGlobalSessionTimeout()); // 1800000
        //配置sessionManager
        sessionManager.setGlobalSessionTimeout(5*60*1000);
        return sessionManager;
    }
    ​
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        securityManager.setCacheManager(getEhCacheManager());
        securityManager.setSessionManager(getDefaultWebSessionManager());
        return securityManager;
    }

 

Guess you like

Origin blog.csdn.net/u014748504/article/details/107890369