1. 程式人生 > >Shiro集成web環境[Springboot]-認證與授權

Shiro集成web環境[Springboot]-認證與授權

跳轉 anon cache action 過濾器 utf-8 tor def nbsp

Shiro集成web環境[Springboot]--認證與授權

在登錄頁面提交登陸數據後,發起請求也被ShiroFilter攔截,狀態碼為302

<form action="${pageContext.request.contextPath}/user/login" method="post">
    Username:<input type="text" name="username"></br>
    Password:<input type="password" name="password"></br>
    <input type="submit" value="提交">
</form>

所以,必須將控制器的請求全部設置為匿名資源

@Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> map = new HashMap<>();
        //多個過濾器  AnonymousFilter  匿名過濾器   anon
        // FormAuthenticationFilter 認證過濾器 authc
        map.put("/**","authc");
        map.put("/user/*","anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        shiroFilterFactoryBean.setLoginUrl("/main/login.jsp");
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager getSecurityManager(Realm realm){
        //web環境下securityManage的實現類為DefaultWebSecurityManager
        SecurityManager securityManager = new DefaultWebSecurityManager();
        ((DefaultWebSecurityManager) securityManager).setRealm(realm);
        return securityManager;
    }

再次發起請求,ok 但由於認證未設置 所以沒有成功的跳轉。

開發自定義Realm--認證與授權方法全部實現

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        String principal =(String) authenticationToken.getPrincipal();
        User user= new User();
        user.setUsername(principal);
        User user1 = userMapper.selectOne(user);
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user1.getPassword(),ByteSource.Util.bytes("salt"),this.getName());
        return authenticationInfo;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        System.out.println("================================");
        User user= new User();
        user.setUsername(primaryPrincipal);
        User user1 = userMapper.selectOne(user);
        if(primaryPrincipal.equals(user1.getUsername())){
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            authorizationInfo.addRole("super");
            authorizationInfo.addStringPermission("user:delete");
            authorizationInfo.addStringPermissions(Arrays.asList("admin:delete","admin:add"));
            return authorizationInfo;
        }
        return null;
    }
}

補充ShiroFilter,將SecurityManager,自定義Realm,CredentialsMatcher,CacheManager全部交由工廠管理:

@Configuration
public class ShiroFilterConf {

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //shiro會對所有資源進行控制,默認不攔截  需要配置
        Map<String,String> map = new HashMap<>();
        //多個過濾器  AnonymousFilter  匿名過濾器   anon
        // FormAuthenticationFilter 認證過濾器 authc
        map.put("/**","authc");
        map.put("/user/*","anon");
        map.put("/index.jsp","anon");
        //多個過濾器組成過濾器鏈
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        //設置認證頁面路徑
        shiroFilterFactoryBean.setLoginUrl("/main/login.jsp");
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager getSecurityManager(Realm realm,CacheManager cacheManager){
        //web環境下securityManage的實現類為DefaultWebSecurityManager
        SecurityManager securityManager = new DefaultWebSecurityManager();
        ((DefaultWebSecurityManager) securityManager).setRealm(realm);
        ((DefaultWebSecurityManager) securityManager).setCacheManager(cacheManager);
        return securityManager;
    }

    @Bean
    public Realm getRealm(CredentialsMatcher credentialsMatcher){
        MyRealm myRealm = new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher);
        return myRealm;
    }

    @Bean
    public CredentialsMatcher getCredentialsMatcher(){
        HashedCredentialsMatcher hm = new HashedCredentialsMatcher();
        hm.setHashAlgorithmName("MD5");
        hm.setHashIterations(1024);
        return hm;
    }

    @Bean
    public CacheManager getCacheManager(){
        CacheManager cacheManager = new EhCacheManager();
        return cacheManager;
    }
}

測試index頁面

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<shiro:authenticated>
    hello:<shiro:principal></shiro:principal>&nbsp;&nbsp;<a href="${pageContext.request.contextPath}/user/logout">登出</a>
    <ul>
        <li>專輯</li>
        <li>章節</li>
        <li>用戶</li>
        <shiro:hasRole name="super">
            <li>管理員</li>
            <shiro:hasPermission name="admin:delete">
                刪
            </shiro:hasPermission>
            <shiro:hasPermission name="admin:add">
                增
            </shiro:hasPermission>
            <shiro:hasPermission name="admin:update">
                改
            </shiro:hasPermission>
        </shiro:hasRole>
    </ul>
</shiro:authenticated>

<shiro:notAuthenticated>
    <a href="${pageContext.request.contextPath}/main/login.jsp">你好請登錄</a>
</shiro:notAuthenticated>
</body>
</html>

shiro中相關的標簽

<shiro:principal></shiro:principal>  //用戶的身份信息
<shiro:authenticated></shiro:authenticated> //認證成功  執行標簽體的內容
<shiro:notAuthenticated></shiro:notAuthenticated> //未認證  執行標簽體內容
//基於角色的權限管理
<shiro:hasRole name="super"></shiro:hasRole>
<shiro:hasAnyRoles name="admin,super"></shiro:hasAnyRoles>
//基於資源的權限管理
<shiro:hasPermission name="user:delete"></shiro:hasPermission>

緩存問題

如果沒有緩存,一個Permission或者role判斷要查詢三次數據庫-username查主體--主體查角色---角色查權限,這樣對於數據庫的壓力太大,需要設置緩存。而且要註意到,在第一次查詢時shiro就會多個Permission或者Role判斷設置一次緩存,就是說,授權方法doGetAuthorizationInfo只走一次。

ehcache主包必須導入,shiro集成時CacheManager是沒有實現的,主包中才有實現類EhCacheManager

    @Bean
    public CacheManager getCacheManager(){
        CacheManager cacheManager = new EhCacheManager();
        return cacheManager;
    }

Shiro集成web環境[Springboot]-認證與授權