springboot整合shiro

shiro知识点快速入门

整合

1.搞一个@Configuration注解的类,有这个注解项目启动自动执行
描述:这个类自动拦截过滤所有的请求做不同的处理,当调用Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);的时候会触发SecurityManager安全管理器的Authenticator认证器的doGetAuthenticationInfo方法来认证

/**
 * @ fileName:SpringShiroConfig
 * @ description:
 * @ author:zhz
 * @ createTime:2022/3/9 14:55
 * @ version:1.0.0
 */
@Configuration //相当于过去的xml   <beans>
public class SpringShiroConfig {

    /**
     * 配置ShiroFilterFactoryBean过滤器 拦截到所有请求,然后做不同的处理
     * @return
     */
    @Bean //<bean id=shiroFilter class=org.apache.shiro.spring.web.ShiroFilterFactoryBean>
    public ShiroFilterFactoryBean shiroFilter(){
        //实例化对象
        ShiroFilterFactoryBean shiroFilterFactoryBean =
                new ShiroFilterFactoryBean();
        //配置当前shiro使用securityManager
        //<property name="securityManager" ref="securityManager"/>
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        //配置未认证通过认证跳转的地址
        shiroFilterFactoryBean.setLoginUrl("/html/login.html");
        //认证成功后,默认跳转地址
        //shiroFilterFactoryBean.setSuccessUrl("");
        //访问未授权的url时跳转地址
        shiroFilterFactoryBean.setUnauthorizedUrl("/html/unauthorized.html");
        //定义放行拦截规则   =号后面配置任意一个字符串都是代表一个底层filter一定不能写错
         // /html/login.html=anon   // anon  不需要认证,就可以访问地址  放行地址
         // /user/logout = logout  // 用户注销配置
         /* # some example chain definitions:
         /admin*//** = authc, roles[admin]  //当地址栏地址含有/admin/**  authc 需要认证,必须登录,  roles[admin] 必须拥有admin角色才可以访问
         /docs/** = authc, perms[document:read] //当地址栏含有/docs/**  authc 需要认证,必须登录, perms[document:read]  必须拥有document:read 权限才可以访问
         /** = authc   // 除了上面单独的配置之外,其他请求全部需要认证 并且该配置必须在其他配置之后
         # more URL-to-FilterChain definitions here*/
        Map filterChainDefinitionMap =new LinkedHashMap();//hashMap   不要使用new HashMap() 无序的  LinkedHashMap获取时会按照放入的顺序
        //放行配置
        filterChainDefinitionMap.put("/html/login.html","anon");
        filterChainDefinitionMap.put("/user/login","anon");
        filterChainDefinitionMap.put("/user/add","anon");
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/imgs/**","anon");
        //登出  前面地址随便写,和地址栏对应  后面 logout必须这样写
        filterChainDefinitionMap.put("/logout","logout");
        //全部需要认证
        filterChainDefinitionMap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }


    /**
     * 实例化SecurityManager  当前用户的幕后主使,所有认证授权等功能都是它来完成
     * @return
     */
    @Bean
    public DefaultWebSecurityManager  securityManager(){
        DefaultWebSecurityManager defaultWebSecurityManager =
                new DefaultWebSecurityManager();
        //依赖注入自定义realm
        defaultWebSecurityManager.setRealm(myCustomRealm());
        return defaultWebSecurityManager;
    }

    /**
     * 实例化自定义realm获取安全数据
     * @return
     */
    @Bean
    public MyCustomRealm myCustomRealm(){
        MyCustomRealm myCustomRealm = new MyCustomRealm();
        myCustomRealm.setCredentialsMatcher(credentialsMatcher());
        return myCustomRealm;
    }

    /**
     * 实例化HashedCredentialsMatcher  配置加密算法和哈希次数
     * @return
     */
    @Bean
    public HashedCredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher =
                new HashedCredentialsMatcher();
        //设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName(BussinessConstant.CredentialsMatcher.HASHEDAGRITHMNAME);
        //设置哈希次数  增加破解难度
        hashedCredentialsMatcher.setHashIterations(BussinessConstant.CredentialsMatcher.HASHEDINTERATIONS);
        return hashedCredentialsMatcher;
    }
}

2.认证和授权方法
描述:特定情况下触发这两个方法的时候

触发情况:

1.doGetAuthenticationInfo执行时机如下

当调用Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);

2.doGetAuthorizationInfo执行时机有三个,如下:

1、subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;

2@RequiresRoles(“admin”) :在方法上加注解的时候;

3[@shiro.hasPermission name = “admin”][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。

方法:

/**
 * @ fileName:MyCustomRealm
 * @ description:
 * @ author:zhz
 * @ createTime:2022/3/9 15:04
 * @ version:1.0.0
 */
public class MyCustomRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    /**
     * 获取角色和权限数据    做授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //该方法执行时,认证一定是通过的,如果认证不过,该方法不会执行
          // 获取认证时放入的第一个参数  
        User user = (User)principalCollection.getPrimaryPrincipal();
        String userName = user.getUserName();
        SimpleAuthorizationInfo simpleAuthorizationInfo =new SimpleAuthorizationInfo();
        List<Role> roleList = userService.queryRoleListByUserName(userName);
        List<Menu> menuList = userService.queryMenuListByUserName(userName);
        //添加角色
        if(!CollectionUtils.isEmpty(roleList)){
            for (Role role : roleList) {
                simpleAuthorizationInfo.addRole(role.getRoleKey());
            }
        }
        //添加权限
        if(!org.springframework.util.CollectionUtils.isEmpty(menuList)){
            for (Menu menu : menuList) {
                if(!StringUtils.hasLength(menu.getPerms())){
                    simpleAuthorizationInfo.addStringPermission(menu.getPerms());
                }
            }
        }
        return simpleAuthorizationInfo;
    }

    /**
     * 获取用户  做认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
      //获取用户名
        String userName =  (String)authenticationToken.getPrincipal();
        //根据用户获取用户信息
        User user = userService.queryUserByUserName(userName);
        //如果对象为空,直接账号错误  代码终止运行
        if(user==null){
            throw new AccountException();
        }
        //获取加密密码
        String password = user.getPassword();
        //获取盐值
        String salt = user.getSalt();
        return new SimpleAuthenticationInfo(user,//第一参数 放主要的信息(用户信息)  当认证成功后,可以通过Subject获取
                password,//第二参数  加密密码 用户注册时,要使用shiro提供的加密算法SHA-512,带上密码和随机盐值经过10次哈希后的结果
                ByteSource.Util.bytes(salt),//第三个参数  随机盐值
                this.getName());  }
}

加密工具:

public class BussinessConstant {

    /**
     * 加密专用常量
     */
    public interface CredentialsMatcher{
        String  HASHEDAGRITHMNAME="SHA-512";
        int    HASHEDINTERATIONS=1024;
    }
}

登陆细节:

1.触发认证的登录方法:

 /**
     * 用户登录
     * @param userName
     * @param password
     */
    @PostMapping("login")
    public String login(String userName,String password){
        //收集用户信息
        UsernamePasswordToken usernamePasswordToken =
                new UsernamePasswordToken(userName, password);
        //获取当前主体(当前用户)
        Subject currentUser = SecurityUtils.getSubject();
        String errorInfo = "";
        try {
            //登录
            currentUser.login(usernamePasswordToken);
            //获取认证成功的用户信息
            User user =  (User)currentUser.getPrincipal();
            //获取安全session
            Session session = currentUser.getSession();
            //存入用户信息
            session.setAttribute("userInfo",user);
            //认证成功后  重定向到部门查询
            return "redirect:/dept/queryAll";
        }catch (AccountException e) {
            e.printStackTrace();
            errorInfo= "1";
        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            errorInfo= "2";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            errorInfo= "3";
        }
         return "redirect:/html/login.html?errorInfo="+errorInfo;
    }

2.这里使用的是实体类做sql执行返回值,需要设置实体类和实体类对应的属性,注意sql查询操作的元素要与实体类属性名字相同,强制的,一般sql都是复杂的不会相同,有两个方法可以是两者相同

 1.通过resultMap标签设置实体类和sql查询的数据
 <!--<resultMap id="map1" type="com.aaa.sbm.entity.Role">
        <id column="role_id" property="roleId"></id>
        <result></result>
    </resultMap>-->
 2. 改别名
 select role_id roleId,role_name as roleName,role_key roleKey from sys_role


<!--namespace 1,绑定接口 2,隔离语句-->
<mapper namespace="com.aaa.sbm.mapper.UserDao">

sql语句

<mapper namespace="com.aaa.sbm.mapper.UserDao">

    <select id="queryAll" resultType="com.aaa.sbm.entity.User">
        select user_id userId,user_name  userName,login_Name loginName,password,salt
        from sys_user where del_flag=0 and status=0
        <if test="userName!=null and userName!=''">
            and user_name=#{userName}
        </if>

    </select>

授权: 获取角色和权限数据

这边是通过方法上的限制去处理权限,当要访问某个方法得时候会先去查看你这个用户得权限,有对应得授权方法,通过方法上的 这三种注解
@RequiresPermissions(“dept:query”) // 判断当前用户是否拥有权限dept:query,如果有就可以执行该方法
@RequiresPermissions(“dept:queryById”) //判断当前用户是否拥有角色代理商,如果有就可以执行该方法
@RequiresRoles(“guanliyuan”) //判断当前用户是否拥有角色管理员,如果有就可以执行该方法

去触发查询权限函数

 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //该方法执行时,认证一定是通过的,如果认证不过,该方法不会执行
          // 获取认证时放入的第一个参数  
        User user = (User)principalCollection.getPrimaryPrincipal();
        String userName = user.getUserName();
        SimpleAuthorizationInfo simpleAuthorizationInfo =new SimpleAuthorizationInfo();
        List<Role> roleList = userService.queryRoleListByUserName(userName);
        List<Menu> menuList = userService.queryMenuListByUserName(userName);
        //添加角色
        if(!CollectionUtils.isEmpty(roleList)){
            for (Role role : roleList) {
                simpleAuthorizationInfo.addRole(role.getRoleKey());
            }
        }
        //添加权限
        if(!org.springframework.util.CollectionUtils.isEmpty(menuList)){
            for (Menu menu : menuList) {
                if(!StringUtils.hasLength(menu.getPerms())){
                    simpleAuthorizationInfo.addStringPermission(menu.getPerms());
                }
            }
        }
        return simpleAuthorizationInfo;
    }

菜单角色权限sql

1查询用户角色权限


 <select id="queryRoleListByUserName" resultType="com.aaa.sbm.entity.Role">
         select role_id roleId,role_name as roleName,role_key roleKey from sys_role r where del_flag=0   and exists
          (
           select 1 from   sys_user_role ur where ur.user_id=
           (select user_id  from sys_user where user_name=#{userName}  and del_flag=0  and status=0)
           and  r.role_id=ur.role_id
          )
    </select>

2.查询用户菜单权限
1通过exists优化sql是关键,也是值得去学习了解得地方

 <select id="queryMenuListByUserName" resultType="com.aaa.sbm.entity.Menu">
         select menu_id menuId,menu_name menuName,perms from sys_menu m where visible=0 and exists(
       select 1 from sys_role_menu rm where  exists(
        select 1 from   sys_user_role ur where user_id=
         (select user_id  from sys_user where user_name=#{userName}  and del_flag=0  and status=0)
         and rm.role_id=ur.role_id
       ) and rm.menu_id=m.menu_id
     )
    </select>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸葛博仌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值