(十二)springboot中shiro的使用

1、引入maven配置

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

 

 

2、建表

用戶表、角色表、權限表、用戶角色表、角色權限表。html

 

用戶表:java

image.png

 

角色表:spring

image.png

 

權限表:news:* 表示有新聞的全部權限(包括增刪改查),而news:add,只有新聞的新增權限。apache

image.png

 

用戶角色表:用戶擁有哪些角色。安全

image.png

 

角色權限表:角色擁有哪些權限。app

image.png

 

3、自定義Realm

自定義realm主要用於用戶的權限驗證以及登陸驗證。maven

自定義realm繼承AuthorizingRealm類,並重寫doGetAuthorizationInfo和doGetAuthenticationInfo方法,doGetAuthorizationInfo方法主要校驗用戶的權限,即該用戶擁有什麼角色以及權限。doGetAuthenticationInfo用於校驗登陸驗證,即用戶的用戶名或者密碼是否正確。ide

 

/**
 * 類名 : shiro的Realm
 * 用法 :
 * 建立人 : shyroke
 * 時間:2018/12/12 17:29
 */
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PermissionMapper permissionMapper;


    /**
     * 受權,即該用戶擁有什麼角色以及權限
     * 步驟:根據用戶名獲取角色以及權限,而後設置到驗證信息類並返回。
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        String userName = principalCollection.getPrimaryPrincipal().toString();

//        獲取該用戶的角色
        List<Role> roles = userMapper.getRolesByUserName(userName);
        Set<String> roleSets = new HashSet<>();

//        獲取該用戶的權限集
        List<Permission> permissions = new ArrayList<>();
        Set<String> permissoinSet = new HashSet<>();

        //將List轉爲Set
        if(roles !=null && roles.size()>0){
            for(Role role:roles){
                roleSets.add(role.getName());
                permissions.addAll(permissionMapper.getPermissionByRoleId(role.getId()));
            }
        }

        //將List轉爲Set
        if(permissions!=null & permissoinSet.size()>0){
            for(Permission p :permissions){
                permissoinSet.add(p.getName());
            }
        }


        info.addRoles(roleSets);
        info.addStringPermissions(permissoinSet);

        return info;
    }


    /**
     * 認證,即用戶帳號密碼是否正確
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//        獲取用戶名和密碼
        String userName = (String)token.getPrincipal();
        String passWord = new String((char[]) token.getCredentials());

//        根據用戶名查找該用戶
        User user =  userMapper.getUserByName(userName);


        if(user == null){
            throw new UnknownAccountException("用戶名不存在");
        }

        if(!user.getPassword().equals(passWord)){
            throw new IncorrectCredentialsException("密碼錯誤");
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getName(),user.getPassword(),getName());

        return info;
    }
}

 

 

4、shiro配置類

/**
 * 類名 :shiro的核心配置類
 * 用法 :
 * 建立人 : shyroke
 * 時間:2018/12/14 15:20
 */
@Configuration
public class ShiroConfigration {

//    設置自定義Realm
    @Bean
    public MyRealm myRealm(){
        return new MyRealm();
    }

//    權限管理,配置主要是Realm的管理認證
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(myRealm());
        return manager;
    }


    /**
     * 設置過濾條件和跳轉條件
     * anon 不生效的緣由:一、map的類型必須是LinkedHashMap 二、anon必須定義在authc以前
     *
     * @param securityManager
     * @return
     */
    @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
            ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
            factoryBean.setSecurityManager(securityManager);

//            設置登陸跳轉
            factoryBean.setLoginUrl("/admin");
            factoryBean.setSuccessUrl("/admin/index");

            //必須爲LinkedHashMap 不然anon不生效
            Map<String,String> map = new LinkedHashMap<>();

            //退出
            map.put("/admin/logout","logout");

            //登陸頁面和登陸驗證不要攔截
            map.put("/admin/login.html","anon");
            map.put("/admin/tologin","anon");

            //設置須要過濾的連接
            map.put("/admin/**","authc");



            factoryBean.setFilterChainDefinitionMap(map);

            return factoryBean;
        }


    /**
     *  開啓Shiro的註解(如@RequiresRoles,@RequiresPermissions),需藉助SpringAOP掃描使用Shiro註解的類,並在必要時進行安全邏輯驗證
     * 配置如下兩個bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)便可實現此功能
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 開啓aop註解支持
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}

 

 

5、調用

代碼以下,當調用Subject.login方法後,會調用自定義Realm的doGetAuthenticationInfo方法校驗用戶名密碼是否正確,若是不正確則拋出對應異常,controller層捕獲並處理異常。ui

AuthenticationToken usernamePasswordToken = new UsernamePasswordToken(user.getName(),user.getPassword());

Subject subject = SecurityUtils.getSubject();


try {
    subject.login(usernamePasswordToken);
}catch (UnknownAccountException ex) {
    logger.info("用戶名錯誤!");
    return R.error("用戶名錯誤!");
} catch (IncorrectCredentialsException ex) {
    logger.info("密碼錯誤!");
    return R.error("密碼錯誤!");
} catch (AuthenticationException ex) {
    logger.info(ex.getMessage());
    return R.error("系統錯誤,請查看日誌");
} catch (Exception ex) {
    logger.info(ex.getMessage());
    return R.error("系統錯誤,請查看日誌");
}
相關文章
相關標籤/搜索