shiro入门

shiro简介

什么是shiro

         Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。Shiro是Apache软件基金会的一个开源项目。Shiro可以轻松地保护任何应用程序,从命令行应用程序到最大的企业Web应用程序。

shiro三大主体

Shiro的三大主体分别是Subject、SecurityManager、Realm。

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;所有Subject都绑定到SecurityManager上,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;

Subject中比较常用的方法为:

方法作用
login(AuthenticationToken token)登录认证,通过传入合法的认证令牌(AuthenticationToken)进行认证,如果认证成功,则返回true。
logout()登出,清空当前用户的凭证信息并退出登录。
isAuthenticated()判断当前用户是否已经通过认证,如果已经通过认证,则返回true。
isRemembered()判断当前用户是否已经记住登录状态,如果已经记住登录状态,则返回true。
getPrincipal()获取当前用户的身份标识,可以是用户名、邮箱、手机号等。
getPrincipals()获取当前用户的身份集合,可以包含多个身份标识。
getSession()获取当前用户的会话对象(Subject.Session)。
getSession(boolean create)获取当前用户的会话对象,如果当前用户已经有会话,则返回已有的会话对象;如果当前用户没有会话,则创建一个新的会话对象。
hasRole(String roleName)判断当前用户是否拥有指定角色,如果拥有指定角色,则返回true。
hasRoles(Collection roleNames)判断当前用户是否拥有指定角色集合中的所有角色,如果都拥有,则返回true。
isPermitted(String permission)判断当前用户是否拥有指定权限,如果拥有,则返回true。
isPermittedAll(Collection permissions)判断当前用户是否拥有指定权限集合中的所有权限,如果都拥有,则返回true。

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro框架的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器。

SecurityManager提供了以下常用方法:

方法作用
authenticate(AuthenticationToken)用于进行身份认证,接收一个AuthenticationToken参数,返回认证后的Subject对象。如果认证失败,会抛出相应的异常。
logout(Subject)用于注销用户登录信息,接收一个Subject参数,将当前用户的登录信息清除。
createSubject(SubjectContext)用于创建一个Subject对象,接收一个SubjectContext参数,返回创建成功的Subject对象。
hasRole(PrincipalCollection, String)判断当前用户是否拥有某个角色,接收一个PrincipalCollection参数和一个角色名字符串参数,返回一个布尔值表示是否拥有该角色。
isPermitted(PrincipalCollection, String)判断当前用户是否拥有某个权限,接收一个PrincipalCollection参数和一个权限名字符串参数,返回一个布尔值表示是否拥有该权限。
getRealms()获取当前SecurityManager中配置的Realm对象列表,返回一个List对象。
setRealms(List):设置当前SecurityManager中的Realm对象列表,接收一个List对象作为参数。
setSessionManager(SessionManager)设置Session管理器,接收一个SessionManager对象作为参数。

Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

shiro的引入
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.10.0</version>
</dependency>

springboot整合shiro的基本配置

@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(securityManager);//设置安全管理器
    shiroFilterFactoryBean.setLoginUrl("/login");//默认登录的页面
    shiroFilterFactoryBean.setSuccessUrl("/index");//登录成功返回的页面
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");//没有权限访问的页面
    //设置
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    filterChainDefinitionMap.put("/static/**", "anon");
    filterChainDefinitionMap.put("/authc/**", "authc");
    filterChainDefinitionMap.put("/**", "user");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;
}

@Bean
public SecurityManager getSecurityManager(Realm realm) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(realm);
    return securityManager;
}

@Bean
public ShiroRealm getRealm() {
    return new ShiroRealm();
}

}

         springboot在整合shiro中是固定的三个步骤,首先就是要先创建一个ShiroFilterFactoryBean来设置SecurityManager以及过滤器,再创建一个SecurityManager的bean来设置Realm,之后在把自己自定义的Realm设置成bean。其中有一点需要注意的就是在设置ShiroFilterFactoryBean中的filterChainDefinitionMap的过滤链的时候最好使用LinkedHashMap,要是使用HashMap的话可能会出现一些问题。

shiro中常用的Filter

shiro的常用的系统自定义的Filter根据不同的设置来调用不同的过滤器,如下所示:

过滤器对应的过滤器类作用
authcFormAuthenticationFilter需要认证登录才能访问
userUserFilter用户拦截器,表示必须存在用户
anonAnonymousFilter匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,一般用于过滤静态资源
rolesRolesAuthorizationFilter需要指定角色才能访问
portPortFilter需要指定端口才能访问
permsPermissionsAuthorizationFilter需要指定权限才能访问
logoutLogoutFilter登出过滤器,配置指定url就可以实现退出功能
authcBasicBasicHttpAuthenticationFilter指定url需要basic登录
restHttpMethodPermissionFilter将http请求方法转化成相应的动词来构造一个权限字符串
sslSslFilter需要https请求才能访问
noSessionCreationNoSessionCreationFilter禁止创建会话

       shiro在DefaultFilter这个枚举类之中所定义的各种各样的过滤器,其中最常用的也就是authc,anon,在登出的时候或许也会设置logout这个过滤器,而这些过滤器也就是在设置ShiroFilterFactoryBean中的setFilterChainDefinitionMap方法过滤链所用到的。当然也可以自定义实现shiro中的过滤器,通常来说,在自定义实现过滤器都是继承的FormAuthenticationFilter或者AuthenticatingFilter这个类进行。但是自定义过滤器一般是加入一些其他的东西才会用到,比如用jwt所生成的token来代替shiro自带的。

自定义Realm

      Shiro不是直接处理身份验证和权限控制的,而是通过与应用程序集成的Realm实现。Realm是Shiro身份验证和授权查询的后端数据源,它们通常与本地数据存储库(例如数据库)或远程数据存储库(例如LDAP)一起工作。Shiro具有一组默认的Realm,但您可以选择编写自定义Realm以处理自己的身份验证和授权数据源。

自定义Realm可以满足具体的业务需求,例如:

  1. 集成不同类型的数据源:Shiro默认支持JDBC和LDAP等数据源,但是如果您的应用程序需要使用其他类型的数据源(例如NoSQL数据库或REST API),则需要编写自定义Realm。

  2. 更好的性能:默认Realm需要处理大量权限控制逻辑,如果您想要更好的性能表现,则自定义Realm可以优化访问控制逻辑。

  3. 更好的安全性:默认Realm中的身份验证和授权逻辑是通用的,可能存在一些风险,自定义Realm可以根据具体的业务情况定制相应的安全策略。

需要注意的是,自定义Realm需要自己编写相应的身份验证和授权逻辑,并与应用程序进行整合。

public class ShiroRealm implements AuthorizingRealm {
    @Override
public String getName() {
    return "ShiroRealm";
}
//判断当前Realm是否支持某种类型的Token
@Override
public boolean supports(AuthenticationToken token) {
    return token instanceof UsernamePasswordToken;
}
//认证
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    String username = (String) token.getPrincipal();
    String password = new String((char[]) token.getCredentials());
    // 根据用户名和密码查询用户信息
    User user = userService.getUserByUsernameAndPassword(username, password);
    if (user == null) {
        throw new UnknownAccountException("用户名或密码错误");
    }
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
    return authenticationInfo;
}
//授权
@Override
public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
    String username = (String) principals.getPrimaryPrincipal();
    // 根据用户名查询用户角色和权限信息
    Set<String> roles = userService.getRolesByUsername(username);
    Set<String> permissions = userService.getPermissionsByUsername(username);
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    authorizationInfo.setRoles(roles);
    authorizationInfo.setStringPermissions(permissions);
    return authorizationInfo;
}
}

       AuthorizingRealm是Shiro所提供的一个基于权限控制的Realm实现,它也是Shiro推荐的默认实现方式。与其他的Realm不同的是,AuthorizingRealm不仅仅具有验证身份的功能,还能通过实现doGetAuthorizationInfo()方法来完成授权操作,即根据用户的角色、权限等信息来决定用户是否拥有访问某个资源的权限。因此,如果开发者需要在自定义Realm中实现授权功能,那么继承AuthorizingRealm是一个非常合适的选择。同时,Shiro也为开发者提供了其他的Realm实现,例如:JdbcRealm、IniRealm等等,可以根据具体业务需求来选择使用。

shiro使用redis做缓存

在pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在引入redis的依赖之后则需要配置这三项:

spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0

如果redis有密码的话,则需要通过spring.data.redis.password来配置密码进行连接。之后则是要来自定义自己的Cache和CacheManager进行操作。

public class RedisCache<k,v> implements Cache<k,v> {
      private String CacheName;
    public RedisCache() {
    }

    public RedisCache(String cacheName) {
        this.CacheName = cacheName;
    }

    @Override
    public v get(k k) throws CacheException {
        System.out.println("get = " + k);
        return (v) getRedisTemplate().opsForHash().get(this.CacheName,k.toString());
    }

    @Override
    public v put(k k, v v) throws CacheException {
        System.out.println("k = " + k+",v="+v);
        getRedisTemplate().opsForHash().put(this.CacheName,k.toString(),v);
        return null;
    }

    @Override
    public v remove(k k) throws CacheException {
         getRedisTemplate().opsForHash().delete(this.CacheName,k);
        return null;
    }

    @Override
    public void clear() throws CacheException {
        getRedisTemplate().opsForHash().delete(this.CacheName);
    }

    @Override
    public int size() {
        return getRedisTemplate().opsForHash().size(this.CacheName).intValue();
    }

    @Override
    public Set<k> keys() {
        return getRedisTemplate().opsForHash().keys(this.CacheName);
    }

    @Override
    public Collection<v> values() {
        return getRedisTemplate().opsForHash().values(this.CacheName);
    }
    public RedisTemplate getRedisTemplate(){
        RedisTemplate redisTemplate =(RedisTemplate) ApplicationContextUtils.getApplicationContext().getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());
      redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}
public class RedisCacheManager implements CacheManager {


    @Override
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
        System.out.println(cacheName);
        return new RedisCache<K,V>(cacheName);
    }
}

在通过在配置类里面注册的Realm的bean,来将自定义Cache和CacheManager设置到所需要的Realm中。

@Bean
   public ShiroRealm shiroRealm(){
    ShiroRealm shiroRealm = new ShiroRealm();
    shiroRealm.setCacheManager(new RedisCacheManager());//设置缓存管理器
    shiroRealm.setAuthenticationCacheName("shiroRealmCache");
    shiroRealm.setAuthorizationCacheName("shiroRealmCache");
    shiroRealm.setAuthenticationCachingEnabled(true);
    shiroRealm.setCachingEnabled(true);
    return shiroRealm;
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值