SpringBoot 集成 shiro安全框架

SpringBoot 集成 shiro安全框架

1、导入依赖

<!-- shiro安全框架依赖 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.2</version>
</dependency>
<!--  shiro+redis缓存插件 -->
<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>3.1.0</version>
</dependency> 

2、核心概念

  1. Shiro主要功能:身份认证
    Authentication, 身份证认证,一般就是登录
  2. 授权:
    Authorization, 给用户分配角色或者访问某些资源的权限
  3. 会话管理
    Session Management,用户的会话管理员,多数情况下是web session
  4. 加密
    Cryptography, 数据加解密,比如密码加解密等

shiro关键字

  • Subject (把操作交给SecurityManager):我们把用户或者程序称为主体(如用户,第三方服务,cron作业) ,主体去访问系统或者资源
  • SecurityManager( 关联Realm):安全管理器,Subject的认证和授权都要在安全管理器下进行
  • Realm(Shiro 连接数据的桥梁):数据域,Shiro和安全数据的连接器,好比jdbc连接数据库; 通过realm获取认证授权相关信息
  • Authenticator:认证器,主要负责Subject的认证
  • Authorizer:授权器,主要负责Subject的授权,控制subject拥有的角色或者权限
  • Cryptography:加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的api
  • Cache Manager:缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能

用户的登录流程
在这里插入图片描述

3、shiro验证类方法

//用户是否登陆(验证)成功,验证成功返回true
subject.isAuthenticated()
//检查用户是否有对应的角色
subject .hasRole("root")
//获取subject名
subject. getprincipal()
//检查是否有对应的角色,无返回值,直接在SecurityManager 里面进行判断
subject . checkRole( " admin" )
/ /退出登录
subject. logout();

4、Session管理

在这里插入图片描述

5、shiro内置过滤器

简介:内置过滤器 => 身份验证

  • 核心过滤器类: DefaultFilter, 配置哪个路径对应哪个拦截器进行处理
  1. authc: org.apache.shiro.web.filter.authc.FormAuthenticationFilter
    。需要认证登录才能访问
  2. user: org.apache.shiro.web.filter.authc.UserFilter
    。用户拦截器,表示必须存在用户。
  3. anon: org.apache.shiro.web.filter.authc.AnonymousFilter
    *匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,- -般用于过滤静态资源。
  4. roles: org.apache.shiro.web.filter .authz.RolesAuthorizationFilter
    。角色授权拦截器,验证用户是或否拥有角色。
    。参数可写多个,表示某些角色才能通过,多个参数时写roles[“admin,user”], 当有多个参数时必须每个
    参数都通过才算通过
  5. perms: org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
    。权限授权拦截器,验证用户是否拥有权限
    。参数可写多个,表示需要某些权限才能通过,多个参数时写perms[“user, admin”], 当有多个参数时必须每个参数都通过才算可以

在这里插入图片描述

6、实例—前后端分离

自定义Realm

●步骤:
。创建一个类,继承AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm
。重写授权方法doGetAuthorizationInfo
。重写认证方法doGetAuthenticationInfo
●方法:
。当用户登陆的时候会调用doGetAuthenticationInfo
。进行权限校验的时候会调用: doGetAuthorizationInfo
●对象介绍
。UsernamePasswordToken :对应就 是shiro的token中有Principal和Credential
UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
。SimpleAuthorizationInfo: 代表用户角色权限信息
。SimpleAuthenticationInfo :代表该用户的认证信息

public class CustomRealm extends AuthorizingRealm {

    @Autowired
    TeacherDAO teaDao;

//    用户授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        为用户授权
//        (1) 拿到当前登录的用户
        Subject subject = SecurityUtils.getSubject();
        Teacher tea = (Teacher) subject.getPrincipal();
//        (2) 给用户授权,根据他的字段中有的权限进行授权
        info.addStringPermission(tea.getTeaSecurity());

        System.out.println("正在授权");
        return info;
    }

//    用户认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

//          获取封装的用户信息
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
//          验证用户名是否正确
        Teacher tea =  teaDao.findByTeaUser(userToken.getUsername());
        if(tea==null){
            return null;
        }
//          框架验证密码是否正确 ,注意:传递的第一个参数,在用户授权的doGetAuthorizationInfo方法中可以拿到,否则拿不到
        System.out.println(this.getClass().getName());
        return new SimpleAuthenticationInfo(tea,teaDao.findByTeaUser(userToken.getUsername()).getTeaPass(),this.getClass().getName());
    }
}

7、自定义SessionManager管理器

public class CustomSessionManager extends DefaultWebSessionManager {
   
    private static final String AUTHORIZATION = "token";
    private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);

    public CustomSessionManager() {
        super();
    }

    /***
     * 获取sessionid
     */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String sessionid = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
        if (sessionid != null) {
            System.out.println(111111);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
//            判断sessionid是否有效
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionid);
//            表示sessionid为有效
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return sessionid;
        } else {
            System.out.println(22222);
            return super.getSessionId(request, response);
        }
    }
}

搭建shiro环境

import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //  核心类:  ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")
                                                                    DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//      关联DefaultWebSecurityManager对象,设置安全管理器
        bean.setSecurityManager(securityManager);
//        *********************** 检查是否非法访问 ****************************
//        bean.setLoginUrl("/tea/toLogin");                //        (1)检测没有登录时(非法访问),跳转的url,,
//        bean.setSuccessUrl("/tea/index");                //        (2)登陆成功后,跳转的url,
//        bean.setUnauthorizedUrl("/tea/yz");              //        (3)认证不通过跳转,先验证登陆,再验证是否有权限
        /***
         * 添加shiro的内置过滤器
         * anon: 无需认证就可以访问,               游客状态
         * authc: 必须认证了才能访问,            登陆状态
         * user: 必须有 “记住我” 功能才能用
         * perms: 拥有某个资源的权限才能访问,    资源状态 perms[user:add]
         * role: 拥有某个角色权限才能访问         角色状态 role[mldn,admin]
         * 注意:过滤连是顺序执行,从上到下,一般/** 发到最下面
         */
//        必须使用LinkedHashMap对象,表示有序的
        Map<String, String> filterMap = new LinkedHashMap<>();

//        *********************** 为URL路径设置访问权限****************************
        filterMap.put("/upload/**", "anon");
        filterMap.put("/static/**", "anon");
        filterMap.put("/tea/getAll", "authc");

//        ***********************************************************************
//        将添加的验证规则添加到安全管理器中
        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

    //  核心类:  DefaultWebSecurityManager
    @Bean(name = "defaultWebSecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") CustomRealm customRealm,
                                                                  @Qualifier("sessionManager") SessionManager sessionManager,
                                                                  @Qualifier("redisCacheManager") RedisCacheManager redisCacheManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

//      前后端分离必须设置下面的sessionManager,使用自定义的session管理类
        securityManager.setSessionManager(sessionManager);

//      关联自定义类UserRealm
        securityManager.setRealm(customRealm);

//      启用缓存,使用自定义cacheManager,在使用redis缓存时,必须保证启动了redis服务
//        securityManager.setCacheManager(redisCacheManager);



        return securityManager;
    }

    //  核心类:  创建realm对象,需要自定义类,并添加进容器中
    @Bean
    public CustomRealm userRealm() {
        CustomRealm customRealm = new CustomRealm();
//        userRealm.setCredentialsMatcher();    密码加密
        return customRealm;
    }

    //    自定义SessionId,用于前后端分离
    @Bean
    public SessionManager sessionManager(@Qualifier("redisSessionDAO") RedisSessionDAO redisSessionDAO) {
        CustomSessionManager manager = new CustomSessionManager();
//        sessionId超时时间,默认 30分钟,
//        manager.setGlobalSessionTimeout(3000000);

//        配置session持久化,有可能subject.getPrincipal();在强转为vo对象时失败
//        manager.setSessionDAO(redisSessionDAO);
        return manager;
    }

    //    密码加密
//    @Bean
//    public HashedCredentialsMatcher hashedCredentialsMatcher(){
//        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//        hashedCredentialsMatcher.setHashAlgorithmName("md5");
////        散列两次,相当于两次加密
//        hashedCredentialsMatcher.setHashIterations(2);
//    }


//  ******************************************以下需要依赖redis服务************************************************

    //    配置redisManger
    @Bean(name = "RedisManager")
    public RedisManager getRedisManager() {
        RedisManager manager = new RedisManager();
        manager.setHost("localhost");
//        设置Redis的默认端口
        manager.setPort(6379);
        return manager;
    }

    /***
     * 配置cache具体实现类
     * @return
     */
    @Bean
    public RedisCacheManager redisCacheManager(@Qualifier("RedisManager") RedisManager redisManager) {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager);
//        设置过期时间、单位是秒,20s
        redisCacheManager.setExpire(20);
        return redisCacheManager;
    }

    /***
     * 自定义session持久化
     * @return
     */
    @Bean(name = "redisSessionDAO")
    public RedisSessionDAO redisSessionDAO(@Qualifier("RedisManager") RedisManager redisManager) {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager);
        return redisSessionDAO;
    }
}

注解方式

@RequiresRoles(value={"admin", "editor"}, logical= Logical.AND)            
            。需要角色admin和editor两个角色AND表示两个同时成立
@RequiresPermissions (value={"user:add", "user:del"}, logical= Logical.OR)
            。需要权限user:add或user:del权限其中-个,OR是或的意思。
@RequiresAuthentication
            。已经授过权(已经登录过),调用Subject.isAuthenticated()返回true
@RequifesUser
            。身份验证或者通过记住我登录的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值