zoukankan      html  css  js  c++  java
  • Shiro 相关

    Shiro简介

    Subject

    • 即当前的操作的“用户”,该用户是一个抽象概念,由 SecurityManager 管理,所有 Subject 都绑定到 SecurityManager

    SecurityManager

    • 安全管理器,所以安全相关的交互都会经过 SecurityManager ,相当于springmvc中前端控制器DispatcherServlet;

    Realm

    • ,SecurityManager从Realm获取安全数据(如用户、角色、权限)进行校验,可以把 Realm 看成 DataSource,即安全数据源

    认证授权逻辑

    1. 应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager;
    2. 我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。

    整合springboot

    依赖

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

    配置类

    配置步骤

    • 配置realm类
    • 配置SecurityManager管理器类(这里使用的是DefaultWebSecurityManager),关联上面配置的Realm
    • 配置ShiroFilterFactoryBean过滤工厂类,关联配置的SecurityManager、过滤器

    创建配置类

    • shiroFilterFactoryBean.setFilterChainDefinitionMap配置过滤规则实现页面拦截
    • 过滤规则使用map集合装配,使用LinkedHashMap保证存取有序
    • shiroFilterFactoryBean.setLoginUrl设置登陆跳转页面
    package com.hd.config;
    
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    
    @Configuration
    public class ShiroConfig {
        /**
         * 配置Shiro的Web过滤器,拦截浏览器请求并交给SecurityManager处理
         * @return
         */
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            //设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
         /*
         * 添加shiro内置过滤器:
         * anon:无需认证
         * authc:必须认证才可以访问
         * user:如果使用remember的功能才可以访问
         * perms:该资源必须得到资源权限才可以访问
         * roles:该资源必须得到角色权限才可以访问
         */
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
            filterChainDefinitionMap.put("/", "anon");
            filterChainDefinitionMap.put("/css/**","anon");
            filterChainDefinitionMap.put("/js/**","anon");
            filterChainDefinitionMap.put("/img/**","anon");
            filterChainDefinitionMap.put("/register.html","anon");
            filterChainDefinitionMap.put("/public/login.html","anon");
            filterChainDefinitionMap.put("/userlogin","anon");
            filterChainDefinitionMap.put("/error/**","anon");
            filterChainDefinitionMap.put("/findOne","anon");
    
            //设置授权
            filterChainDefinitionMap.put("/user/**","roles[admin]");
    
            filterChainDefinitionMap.put("/**","authc");
    
            //修改跳转页面
            shiroFilterFactoryBean.setLoginUrl("/login.html");
            //自定义授权页面
            shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth.html");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    
            return shiroFilterFactoryBean;
        }
    
        /**
         * 创建DefaultWebSecurityManager
         * @param userRealm
         * @return
         */
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联realm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        /**
         * 创建realm
         * @return 用户realm
         */
        @Bean(name="userRealm")
        public UserRealm getRealm(){
            return new UserRealm();
        }
    }
    

    自定义realm

    认证

    • 继承AuthorizingRealm类,实现doGetAuthorizationInfo(授权)和doGetAuthenticationInfo(认证)方法
    • Subject.login(token)登陆时,会跳转到认证授权的方法
    package com.hd.config;
    
    import com.hd.entity.Role;
    import com.hd.entity.User;
    import com.hd.service.UserService;
    import org.apache.shiro.SecurityUtils;
    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.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.HashSet;
    
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        UserService userService;
    
        /**
         * 授权
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            return null;
        }
    
        /**
         * 认证
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //  获取用户名
            String userName = (String)authenticationToken.getPrincipal();
            //  查询有无该用户
            User user = userService.findUserByName(userName);
            if (null == user) {
                // 没有该用户
                return null;  // 登陆时会抛出UnknownAccountException
            }
    
            /**
             * 密码认证
             * 参数1: 从数据库获取的userduix
             * 参数2: 密码
             * 参数3: 当前realm名称
             */
            return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
        }
    }
    
    

    授权

    • SecurityUtils.getSubject().getPrincipal():获取认证时传递的用户对象
    • SimpleAuthorizationInfo:授权信息对象
    • SimpleAuthorizationInfo.addStringPermission():设置当前用户的权限
    import com.hd.entity.Auth;
    import com.hd.entity.Role;
    import com.hd.entity.User;
    import com.hd.service.RoleService;
    import com.hd.service.UserService;
    import org.apache.shiro.SecurityUtils;
    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.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.HashSet;
    import java.util.List;
    
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        UserService userService;
    
        @Autowired
        RoleService roleService;
    
        /**
         * 授权
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            // 这里拿到的User对象是认证时设置的SimpleAuthenticationInfo类的参数
            User user = (User) SecurityUtils.getSubject().getPrincipal();
            // 授权信息对象
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 获取用户角色
            Role role = userService.findRoleByName(user.getName());
            //todo:role=null ??
    
            // 将角色名称提供给info
            HashSet<String> roles = new HashSet<>();
            roles.add(role.getRole_name());
            info.setRoles(roles);
    
            // 获取角色所有权限,将权限名称提供给info
            List<Auth> auths = roleService.findAuthByRoleId(role.getRole_id());
            for (Auth auth :
                    auths) {
                // 设置当前用户的权限
                info.addStringPermission(auth.getAuth_name());
            }
    
            return info;
        }
    
        /**
         * 认证
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //  获取用户名
            String userName = (String)authenticationToken.getPrincipal();
            //  查询有无该用户
            User user = userService.findUserByName(userName);
            if (null == user) {
                // 没有该用户
                return null;  // 登陆时会抛出UnknownAccountException
            }
    
            /**
             * 密码认证
             * 参数1: 从数据库获取的userduix
             * 参数2: 密码
             * 参数3: 当前realm名称
             */
            return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
        }
    }
    

    登陆

    	/**
    	 *	登录验证
    	 */
    	@PostMapping(value = "/userlogin")
    	public String user_login(String username, String password, Model model){
    		// 封装当前用户数据
    		UsernamePasswordToken token = new UsernamePasswordToken(username,password);
    		// 获取当前用户
    		Subject currentUser = SecurityUtils.getSubject();
    
    		try {
    			// 执行登陆操作
    			// 主体提交登录请求到SecurityManager
    			currentUser.login(token);
    		}catch (IncorrectCredentialsException ice){
    			model.addAttribute("msg","密码不正确");
    		}catch(UnknownAccountException uae){
    			model.addAttribute("msg","账号不存在");
    		}catch(AuthenticationException ae){
    			model.addAttribute("msg","状态不正常");
    		}
    		if(currentUser.isAuthenticated()){
    			return Result.ok("auth success");
    		}else{
    			token.clear();
    			return Result.build(100001, "auth fail");
    		}
    	}
    

    Shiro 内置过滤器及实现类

    Filter Name Class
    anon org.apache.shiro.web.filter.authc.AnonymousFilter
    authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
    authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
    logout org.apache.shiro.web.filter.authc.LogoutFilter
    noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter
    perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
    port org.apache.shiro.web.filter.authz.PortFilter
    rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
    roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
    ssl org.apache.shiro.web.filter.authz.SslFilter
    user org.apache.shiro.web.filter.authc.UserFilter

    自定义Shiro Filter

    • 继承shiro过滤器(AccessControlFilter),重写onAccessDenied、isAccessAllowed
    • isAccessAllowed:判断是否登录,在登录的情况下会走此方法,此方法返回true直接访问控制器
    • onAccessDenied:是否是拒绝登录,没有登录的情况下会走此方法,此方法返回true直接访问控制器
    public class UserFilter extends AccessControlFilter {
    
        @Override
        protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
            return false;
        }
    
        @Override
        protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            //获取用户
            User sessionUser = (User) request.getSession().getAttribute("user");
            if (sessionUser != null) {
                //已经登陆,放行
                return true;
            } else {
                //在Cookie中获取token
                String loginToken = CookieUtil.findCookieByName(request, "loginToken");
                if (StringUtils.isNotBlank(loginToken)) {
                    //根据token找用户
                    UserService userService = (UserService)SpringContextUtil.getBean(UserService.class);
                    User userByToken = userService.getUserByToken(loginToken);
                    if (userByToken != null) {
                        //有对应token的用户,保存到session,放行
                        request.getSession().setAttribute("user", userByToken);
                        return true;
                    } else {
                        //没有对应用户,清除Cookie
                        CookieUtil.clearCookie(request, response, "loginToken");
                        return false;
                    }
                } else {
    
                    //没有cookie,也没有登陆。是index请求获取用户信息,可以放行
                    if (request.getRequestURI().contains("session")) {
                        return true;
                    }
    
                    //没有cookie凭证,跳转到登陆页
                    response.sendRedirect("/login.html");
                    return false;
                }
            }
        }
    }
    

    filter、realm中使用SpringBean

    shiro中自定义的filter和realm中并没有被注入到Spring容器中,如果想要在filter中使用SpringBean,可以使用设置属性的方式

    public class PasswordFilter extends AccessControlFilter{
        // 自定义的Filter中StringRedisTemplate来作为缓存的操作,此属性需要在Spring中获取
        private StringRedisTemplate redisTemplate;
        ...
    }
    

    **用已经注入到容器的类,去设置过滤器属性,即将stringRedisTemplate赋值给PasswordFilter **

    @Component
    public class ShiroFilterChainManager {
    
        private final StringRedisTemplate stringRedisTemplate;
    
        @Autowired
        public ShiroFilterChainManager(StringRedisTemplate stringRedisTemplate) {
            this.stringRedisTemplate = stringRedisTemplate;
        }
    
        public Map<String, Filter> initFilterMap() {
            Map<String, Filter> filterMap = new LinkedHashMap<>();
            PasswordFilter passwordFilter = new PasswordFilter();
            passwordFilter.setRedisTemplate(stringRedisTemplate);
            filterMap.put("auth", passwordFilter);
            filterMap.put("jwt", jwtFilter);
            return filterMap;
        }
    }
    

    shiro配置类

    @Configuration
    public class ShiroConfig {
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager, ShiroFilterChainManager shiroFilterChainManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            // 设置过滤器链
            shiroFilterFactoryBean.setFilters(shiroFilterChainManager.initFilterMap());
          ...
    }
    

    注解

    缓存管理

    Memory

    Redis

    Session管理

  • 相关阅读:
    《滑动到顶部悬浮功能条》源代码学习整理笔记
    eclipse中Build Path-Add to Build Path相应到androidstudio的设置
    UML视图(九)部署图
    ios 字典转模型
    Centos 6.5使用Bumblebee关闭N卡,冷却你的电脑
    oracle if then else
    setAnimationTransition:forView:cache: 运行动画时背景色问题
    数据恢复软件使用经验-支持U盘,手机SD卡,硬盘数据,解决图片恢复后打不开的问题
    ZOJ1109_Language of FatMouse(STL/map)
    navicat中文破解版,navicat破解版,navicat for mysql10.0.11简体中文破解版
  • 原文地址:https://www.cnblogs.com/xiongyungang/p/12660466.html
Copyright © 2011-2022 走看看