shiro初步学习

    科技2022-09-06  133

    Shiro

    核心组件

    UsernamePasswordToken: shiro用来封装用户登录信息,使用用户的登录信息来创建令牌TokenSecurityManager :shiro的核心部分,负责安全认证和授权Subject :Shiro的一个抽象概念,包含了用户信息Realm :开发者自定义的模块,验证和授权的逻辑全部写在Realm中AuthenticationInfo:用户的角色信息集合,认证时使用AuthorzationInfo:用户的权限信息集合,授权时使用DefaultWebSecurityDManager:安全管理器,开发者自定义Realm需要注入到进行管理才能生效ShiroFilterFactoryBean:过滤器工厂

    功能简介

    Authentication :身份认证/登录

    Authorization :授权,权限验证

    SessionManagement:会话管理

    Cryptography:加密

    WebSupport : Web支持

    Caching: 缓存

    Concurrency: 并发验证

    Testing:测试

    “Run As”:允许一个用户假装另一个用户

    Remember me:记住我

    Spring Boot 整合 shiro

    认证过滤器

    anon:无需认证

    autc:必须认证

    authBasic:需要通过HttpBasic认证

    user:不一定通过认证,只要曾经被shiro记录即可,(记住我)

    授权过滤器

    perms:必须拥有某个权限

    roles:必须拥有某个角色

    prot:必须 指定端口

    rest:请求必须基于 RestFul

    ssl:必须是安全的url请求 ,协议HTTPS

    shiro依赖

    <!--springBoot 整合Shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> <!--shiro-ehCache依赖--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.2</version> </dependency> <!--Redis缓存依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>

    shiro配置类

    @Configuration public class MyShiRo { /** * 将自定义的Realm组件交给Bean容器 * @return */ @Bean public UserRealm userRealm(){ //创建自定义Realm对象 UserRealm userRealm = new UserRealm(); // 匹配器 对象 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); // 加密方式名 credentialsMatcher.setHashAlgorithmName("MD5"); // 加密次数 credentialsMatcher.setHashIterations(1024); // 将匹配器 存入对象中 userRealm.setCredentialsMatcher(credentialsMatcher); // 设置 缓存管理对象 userRealm.setCacheManager(new RedisCacheManager()); // 开启 角色认证全局缓存 userRealm.setAuthenticationCachingEnabled(true); // 设置 角色认证 缓存名 userRealm.setAuthenticationCacheName("authentication"); // 开启 权限授权全局缓存 userRealm.setAuthorizationCachingEnabled(true); // 设置 权限授权 缓存名 userRealm.setAuthorizationCacheName("authorization"); return userRealm; } /** * 将DefaultWebSecurityManager组件 交给Bean容器 * @param userRealm * @return */ @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager manager=new DefaultWebSecurityManager(); manager.setRealm(userRealm); return manager; } /** * 创建ShiroFilter工厂 交给Bean容器 * @param defaultWebSecurityManager * @return */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ //创建ShiroFilter工厂对象 ShiroFilterFactoryBean factoryBean= new ShiroFilterFactoryBean(); //将安全管理加到工厂对象 factoryBean.setSecurityManager(defaultWebSecurityManager); //设置 认证,权限集 Map<String,String> map=new HashMap<String, String>(); map.put("/index","authc"); map.put("/","authc"); map.put("/vip","perms[manage]"); map.put("/admin","roles[admin]"); map.put("/login","anon"); map.put("/register","anon"); //将权限集 放入到 工厂对象中 factoryBean.setFilterChainDefinitionMap(map); //设置 登录页面 factoryBean.setLoginUrl("/login"); //设置 无授权页面 factoryBean.setUnauthorizedUrl("/index"); return factoryBean; } }

    shiro-自定义realm

    public class UserRealm extends AuthorizingRealm { /** * 权限授权 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获取subject对象 Subject subject= SecurityUtils.getSubject(); //获取subject对象里的 object对象 User user = (User) subject.getPrincipal(); //Set集合 放权限名 Set<String> set = new HashSet<>(); set.add(user.getRole()); //将权限集放进SimpleAuthorizationInfo对象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(set); //将权限 与角色相连 info.addStringPermission(user.getPerms()); return info; } /** * 角色认证 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //封装前台用户信息 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; UserServiceImpl userService = (UserServiceImpl) SpringUtils.getBean("userServiceImpl"); //前台传的用户名在数据库里查找 User user = userService.findUserByName(token.getUsername()); if(user !=null){ //返回一个AuthenticationInfo对象 return new SimpleAuthenticationInfo(user,user.getPassword(), new MyByteSource(user.getSalt()),this.getName()); } return null; } }

    controller层

    @PostMapping("/login") public String loginAuthentication(String username, String password, Model model){ // subject对象 Subject subject= SecurityUtils.getSubject(); //封装用户信息 UsernamePasswordToken token=new UsernamePasswordToken(username,password); try{ subject.login(token); return "redirect:/"; }catch (UnknownAccountException e){ e.printStackTrace(); model.addAttribute("msg","账户错误"); return "login"; }catch (IncorrectCredentialsException e){ e.printStackTrace(); model.addAttribute("msg","密码错误"); return "login"; } }

    加密(MD5)

    在shiro配置类 userRealm中加上

    // 匹配器 对象 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); // 加密方式名 credentialsMatcher.setHashAlgorithmName("MD5"); // 加密次数 credentialsMatcher.setHashIterations(1024); // 将匹配器 存入对象中 userRealm.setCredentialsMatcher(credentialsMatcher);

    加密方式 Service层

    public void register(User user) { //获取八位数的盐 String salt= SaltUtils.getSalt(8); //将盐保存到数据里 user.setSalt(salt); //明文密码进行md5+salt+hash散列 Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024); //将md5密码赋值给数据里的password user.setPassword(md5Hash.toHex()); userMapper.insertUser(user); }

    salt工具类

    public class SaltUtils { public static String getSalt(int n){ char[] chars = "QWERTYUIOPLKJHGFDSAZXCVBNMqwertyuioplkjhgfdsazxcvbnm1234567890!@#$%^&*".toCharArray(); StringBuilder sb= new StringBuilder(); for (int i = 0; i < n; i++) { char achar=chars[new Random().nextInt(chars.length)]; sb.append(achar); } return sb.toString(); } }

    缓存(EhCache,RedisCache)

    依赖

    <!--shiro-ehCache依赖--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.2</version> </dependency>

    在shiro配置类 自定义userRealm

    // 设置 缓存管理对象 userRealm.setCacheManager(new EhCacheManager()); // 开启 角色认证全局缓存 userRealm.setAuthenticationCachingEnabled(true); // 设置 角色认证 缓存名 userRealm.setAuthenticationCacheName("authentication"); // 开启 权限授权全局缓存 userRealm.setAuthorizationCachingEnabled(true); // 设置 权限授权 缓存名 userRealm.setAuthorizationCacheName("authorization");

    Redis缓存

    实现shiro缓存底层的cacheManager 和cache 接口

    实现cache

    /** * 实现Shiro中的Cache * @author yd * @version 1.0 * @date 2020/10/4 8:46 */ public class MyRedis<K,V> implements Cache<K,V> { public String cacheName; public MyRedis() { } public MyRedis(String cacheName) { this.cacheName = cacheName; } public RedisTemplate redisTemplate(){ RedisTemplate redisTemplate = (RedisTemplate) SpringUtils.getBean("redisTemplate"); redisTemplate.setKeySerializer(new StringRedisSerializer()); return redisTemplate; } @Override public V get(K k) throws CacheException { return (V) redisTemplate().opsForHash().get(this.cacheName,k.toString()); } @Override public V put(K k, V v) throws CacheException { redisTemplate().opsForHash().put(this.cacheName,k.toString(),v); return null; } @Override public V remove(K k) throws CacheException { return (V) redisTemplate().opsForHash().delete(this.cacheName,k.toString()); } @Override public void clear() throws CacheException { redisTemplate().delete(this.cacheName); } @Override public int size() { return redisTemplate().opsForHash().size(this.cacheName).intValue(); } @Override public Set<K> keys() { return redisTemplate().opsForHash().keys(this.cacheName); } @Override public Collection<V> values() { return redisTemplate().opsForHash().values(this.cacheName); } }

    实现CacheManager

    /** * 实现Shiro的CacheManager * @author yd * @version 1.0 * @date 2020/10/4 8:43 */ public class RedisCacheManager implements CacheManager { @Override public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException { return new MyRedis<K,V>(cacheName); } }
    Processed: 0.010, SQL: 9