Shiro & Spring Security

实际开发中:

一 、 shiro已经满足基本的安全需求,使用简单,需要用数据库的role和permission表来注入实现

(1)相关注解:

@RequiresRoles("xxx")        //角色控制
@RequiresPermissions("xxx")     //功能权限控制

(2)配置类ShiroConfig模板 :

package com.kevin.springbootkevin1.config;

import com.kevin.springbootkevin1.realm.UserRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
public class ShiroConfig {

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
     * 3、部分过滤器可指定参数,如perms,roles
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(org.apache.shiro.mgt.SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

        //配置静态资源允许访问
        filterChainDefinitionMap.put("/user/login","anon");
        filterChainDefinitionMap.put("/user/loginAction","anon");

        //filterChainDefinitionMap.put("/css/**","anon");
        //filterChainDefinitionMap.put("/index","anon");

        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/user/login");

        // 未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        Map<String, Filter> filters=new HashMap<String,Filter>();
        shiroFilterFactoryBean.setFilters(filters);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public EhCacheManager getEhCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return em;
    }
    // 开启Controller中的shiro注解
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }
    /**
     * 配置org.apache.shiro.web.session.mgt.DefaultWebSessionManager
     * @return
     */
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager(){
        DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(getMemorySessionDAO());
        defaultWebSessionManager.setGlobalSessionTimeout(4200000);
        defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
        defaultWebSessionManager.setSessionIdCookieEnabled(true);
        defaultWebSessionManager.setSessionIdCookie(getSimpleCookie());
        return defaultWebSessionManager;
    }
    /**
     * 配置org.apache.shiro.session.mgt.eis.MemorySessionDAO
     * @return
     */
    @Bean
    public MemorySessionDAO getMemorySessionDAO(){
        MemorySessionDAO memorySessionDAO=new MemorySessionDAO();
        memorySessionDAO.setSessionIdGenerator(javaUuidSessionIdGenerator());
        return memorySessionDAO;
    }
    @Bean
    public JavaUuidSessionIdGenerator javaUuidSessionIdGenerator(){
        return new JavaUuidSessionIdGenerator();
    }
    /**
     * session自定义cookie名
     * @return
     */
    @Bean
    public SimpleCookie getSimpleCookie(){
        SimpleCookie simpleCookie=new SimpleCookie();
        simpleCookie.setName("security.session.id");
        simpleCookie.setPath("/");
        return simpleCookie;
    }
    @Bean
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(userRealm);
        //  <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
        dwsm.setCacheManager(getEhCacheManager());
        dwsm.setSessionManager(getDefaultWebSessionManager());
        return dwsm;
    }
    @Bean
    public UserRealm userRealm(EhCacheManager cacheManager) {
        UserRealm userRealm = new UserRealm();
        userRealm.setCacheManager(cacheManager);
        return userRealm;
    }
    /**
     * 开启shrio注解支持
     * @param userRealm
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(UserRealm userRealm){
        AuthorizationAttributeSourceAdvisor aasa=new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(getDefaultWebSecurityManager(userRealm));
        return aasa;
    }

}

(3)realm层 重要的两个方法:

AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc):控制角色权限
AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException:控制登录

注:

POM引入:

<!--Shiro安全-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.0</version>
        </dependency>

使用方法:

1.创建数据库user、role、permission表,分别对应用户表、角色表、权限表。

2.配置ShiroConfig,如上图第(2)项,

说明:

这段代码的目的:添加允许访问的请求(使这些请求能通过,不被拦截)。

其他的根据注释、查阅资料学习。

3.书写realm层

ex:

package com.kevin.springbootkevin1.realm;
import com.kevin.springbootkevin1.bean.User;
import com.kevin.springbootkevin1.mapper.PermissionMapper;
import com.kevin.springbootkevin1.mapper.RoleMapper;
import com.kevin.springbootkevin1.service.IUserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * <p>
 *  用户权限类-持久层
 * </p>
 *
 * @author Jia Xin
 * @since 2020-02-11
 */
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private IUserService userService;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    //控制角色权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        //获取登录用户名
        String username = (String)pc.getPrimaryPrincipal();
        //定义一个权限管理器
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info = userService.addRolePermissions(info,username);
        System.out.println("username:"+username+"," +
                "角色和权限信息:" + info);
        return info;
    }

    //控制登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
        AuthenticationInfo info;
        //token携带的主键username
        String username = (String)at.getPrincipal();
        //第一步拦截-如果前端传来的为空
        if(username == null) {
            return null;
        }
        //通过用户名查询得到user实体
        User user = userService.selectUserByUsername(username);
        if(user != null){       //username.equals(user.getUsername())
            String  md5Hash = new Md5Hash(user.getPassword() , "123").toString();
            info = new SimpleAuthenticationInfo(username, md5Hash, getName());
            return info;
        } else {
            //用户名不存在
            return null;
        }
    }
}

注:selectUserByUsername函数写在service层下的。

4.书写Controller层:

登录请求:为了验证,用了md5哈希加密。

subject.login(token);  shiro的安全验证。

如果抛出异常,则:验证不成功;反之,则成功。

//登录验证
    @GetMapping(value = "/loginAction")
    //@RequestBody Map<String, Object> user
    public String loginAction(String username ,String password) {
//        String username = user.get("username").toString();
//        String password = user.get("password").toString();
        //添加用户认证信息
        Subject subject = SecurityUtils.getSubject();
        //用哈希对密码加密
        String md5Hash = new Md5Hash(password, "123").toString();
        //AuthenticationToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        UsernamePasswordToken token = new UsernamePasswordToken(username, md5Hash);
        //System.out.println("subject.isPermitted() => " + subject.isPermitted("sys:delete"));
        try {
            //登录成功
            subject.login(token);
            return "LoginS";
        } catch (Exception e) {
            //登录失败
            return "LoginF";
        }
    }

5.模拟数据:

user表

role表

permission表

zhangsan是admin角色,roleid=1,没有任何权限。

lisi是teacher角色,roleid=2,有sys:add   sys:edit   sys:delete 权限.

6.加注解:

这里演示第一个角色控制。

7.验证:

A. 首先lisi登陆:

他是teacher角色,没有权限。

发起getuser请求,出现异常,shiro控制进行拦截了,在意料之中。

而且springboot console控制台有记录:

2020-02-18 00:15:27.312  WARN 11764 --- [nio-8088-exec-6] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.apache.shiro.authz.UnauthorizedException: Subject does not have role [admin]]

B. 然后zhangsan登陆:

他是admin角色,三个权限。

发起getuser请求,取到结果,未被拦截,在意料之中。

8.演示到此。

二 、 Spring Security包含shiro所能完成得功能,很好地支持Spring应用,能胜任大型软件所需的安全功能需求。

学习资料:Spring Boot Security 详解

发布了71 篇原创文章 · 获赞 22 · 访问量 6021

猜你喜欢

转载自blog.csdn.net/Kevin__Coder/article/details/104268151
今日推荐