Shiro集成web环境[Springboot]-认证与授权

Posted AGENTFITZ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shiro集成web环境[Springboot]-认证与授权相关的知识,希望对你有一定的参考价值。

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]-认证与授权的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot 集成Shiro--官网

SpringBoot之----了解Shiro安全框架

Springboot学习Shiro快速入门及与SpringBoot集成

SpringBoot集成Shiro

springboot集成shiro实现用户登录认证

springboot-shiro chapter01——创建springboot web环境