Shiro手把手教你上手(通俗易懂版,看完即用)

Shiro(Springboot版)

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序

1.Shiro的三大核心API

1.1 Subject:用户主体,把操作交给SecurityManager
1.2 SecurityManager:安全管理器,与Realm相关联
1. 3 Realm:Shiro数据连接的桥梁,保证数据访问控制,用于身份验证与权限获取,这也是shiro的主要功能

2.添加依赖

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

3.Controller

之前都是从前台获取username与password来进行数据库验证,然后判断是不是相同,但是现在是运用shiro验证

Subject subject=SecurityUtils.getSybject();
<!--定义一个令牌,可以理解为登录的凭证-->
<!--将获得的用户名和密码放进去-->
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
<!--进行登录验证,需要进行异常处理-->
 try {
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return  "redirect:/mangae/login";
        }

4.自定义一个Realm

既然进行了登录,那么就到了realm登场了,shiro如何验证与授权接下来你就懂了
4.1.自己做一个realm,必须继承AuthorizingRealm类,继承后便可生成两个方法

public class Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
}

生成的方法如上图可见
AuthenticationInfo 便是认证,也就是来判断用户登录是否成功
AuthorizationInfo 便是授权,是通过数据库来查看用户有的权限,并且存入,好在之后访问页面时候来判断是否有该权限
4.2 AuthenticationInfo 方法

@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //这里便是我们从subject中运用.login传来的令牌,从中取出用户名
        UsernamePasswordToken userToken= (UsernamePasswordToken)authenticationToken;
        String username=userToken.getUsername();
        //这便是通过调用service中方法查出是这个username的对象
        Manager manger= manageService.findByUsername(username);
        //这里是shiro还带了盐的功能,进行加密
        Config config = configService.findByKey("salt");
        String salt = config.getValue();
        if (manger==null){
            return null;//抛出异常  UnknownAccountException
        }
        //这里便是进行验证的操作,在这里面会进行验证传来的密码与数据库获得的是否一致
        //第一个传的最好是对象,以便于验证时候使用,可以获取到
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                manger, //用户
                manger.getPassword(), //密码
                ByteSource.Util.bytes(salt), //盐
           ""
        );
        return authenticationInfo;
    }

4.3 AuthenticationInfo方法

  @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    //这里获得到的就是authenticationInfo中的第一个变量
        Manager manager=(Manager)principalCollection.getPrimaryPrincipal();
       //设置角色字符串及权限字符串 
       Set<String> roles = new HashSet<>(); 
       Set<String> perms = new HashSet<>(); 
       Set<Role> roleSet = admin.getRoles(); 
       roleSet.forEach(role -> { roles.add(role.getRole()); 
       role.getPermissions().forEach(permission -> perms.add(permission.getPerm())); });
       //设置角色字符串 
       info.setRoles(roles); 
       //设置权限字符串 
       info.setStringPermissions(perms);
        return info;
    }

通俗来说,这一步就是查出来你所拥有的角色以及你所拥有的权限,在之后的ShiroFilterFactoryBean中来判断你是否有访问某些路径的权限
4.4 贴上完整代码

public class Realm extends AuthorizingRealm {
    @Resource
    private ManageService manageService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private ConfigService configService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Manager manager=(Manager)principalCollection.getPrimaryPrincipal();
        //查询角色字符串集合
        Set<String> roles = new HashSet<>();
        //查询权限字符串集合
        Set<String> permissions = new HashSet<>();
		Set<Role> roleSet = admin.getRoles();
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //从数据库读出  所拥有的权限  显示出来
       roleSet.forEach(role -> { roles.add(role.getRole()); 
       role.getPermissions().forEach(permission -> 
       perms.add(permission.getPerm())); });
        //将拥有的权限和角色存入
        info.setRoles(roles);
        info.setStringPermissions(permissions);
        return info;
    }
//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken userToken= (UsernamePasswordToken)authenticationToken;
        String username=userToken.getUsername();
        System.out.println(username);
        Manager manger= manageService.findByUsername(username);
        Config config = configService.findByKey("salt");
        String salt = config.getValue();
        if (manger==null){
            return null;//抛出异常  UnknownAccountException
        }
        //验证
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                manger, //用户名
                manger.getPassword(), //密码
                ByteSource.Util.bytes(salt), //盐
           ""
        );
        return authenticationInfo;

    }
}

这一部分就可以理解为,查看出数据库该角色所拥有的权限,也就是知道了那些界面能够访问

5.Shiro的配置类

5.1 Realm

    @Bean
    public Realm realm(){
    	Realm realm = new Realm();
    	//最简单的情况就是明文直接匹配,然后就是加密匹配,这里的匹配工作则就是交给
    	//CredentialsMatcher来完成的
    	//使用加密匹配
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }

@Bean注解重中之重,因为用的配置类
5.2 创建安全管理器DefaultWebSecurityManager

@Bean("securityManager")
    public SecurityManager defaultWebSecurityManager(@Qualifier("managerRealm") ManagerRealm managerRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(managerRealm);
       /* List<Realm> realms=new ArrayList<>();
        realms.add(managerRealm);
       realms.add(userinfoRealm);
        securityManager.setRealms(realms);*/
        return securityManager;
    }

5.3 创建ShiroFilterFactoryBean

  @Bean("shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /*
            anon:无需认证就可以访问
            authc:必须认证才可以访问
            user:必须拥有  记住我功能才能用
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色权限才能访问
         */
        Map<String,String> filterMap=new LinkedHashMap<>();
      /*  filterMap.put("/manage/list","authc");*/
      //这个意思是要去访问manage下面的路径时候,如果没有登录不能访问
        filterMap.put("/manage/**","authc");
       //无权限时候访问到登录页面
        bean.setUnauthorizedUrl("/m/login");
        //登录路径
        bean.setLoginUrl("/m/login");
        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

5.5盐
说到了盐,是shiro的底层源码有的,可以帮助我们直接使用md5加密,注册时可以通过使用

SimpleHash simpleHash= new SimpleHash("md5","未加密的密码","盐",加密次数);

来进行给获得到的密码加密,这样加密的方法相同,或得到的密码值也相同

@Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1);//加密的次数;
        return hashedCredentialsMatcher;
    }

5.4 贴上完整代码

@Configuration
public class ShiroConfig {
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /*
            anon:无需认证就可以访问
            authc:必须认证才可以访问
            user:必须拥有  记住我功能才能用
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色权限才能访问
         */
        Map<String,String> filterMap=new LinkedHashMap<>();
      //这个意思是没有登录的访问/manage/任意的,都不行
        filterMap.put("/manage/**","authc");
       //无权限时候访问 去登录页面也就是
        bean.setUnauthorizedUrl("/m/login");
        filterMap.put("/manage/**","pers[sajdla]");
        bean.setLoginUrl("/m/login");
        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }
    @Bean("securityManager")
    public SecurityManager defaultWebSecurityManager(@Qualifier("managerRealm") ManagerRealm managerRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(managerRealm);
       /* List<Realm> realms=new ArrayList<>();
        realms.add(managerRealm);
       realms.add(userinfoRealm);
        securityManager.setRealms(realms);*/
        return securityManager;
    }
    @Bean
    public ManagerRealm managerRealm(){
     	Realm realm = new Realm();
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }
    /*@Bean
    public UserinfoRealm userinfoRealm(){
        return new UserinfoRealm();
    }*/
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//加密的次数;
        return hashedCredentialsMatcher;
    }

    //启用 controller 的权限注解
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(manager); return advisor; }
        // 开启代理
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值