Shiro框架快速上手操作学习

参考博客:

https://blog.csdn.net/aimashi620/article/details/80880007
https://blog.csdn.net/pengjwhx/article/details/84867112?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-4&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-4
https://blog.csdn.net/weixin_30263277/article/details/95053586?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-26&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-26
https://blog.csdn.net/qq_41717874/article/details/84989988?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

1.shiro功能

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。

在这里插入图片描述
主要功能
Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份,通常用来做登录验证的;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web 支持,可以非常容易的集成到 Web 环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

2 Shiro的架构

在这里插入图片描述
可以看到:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject;

Subject:主体,代表了当前 “用户”

SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;

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

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

3 身份验证

在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份:

principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个 principals,但只有一个 Primary principals,一般是用户名 / 密码 / 手机号。

credentials:证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。
在这里插入图片描述流程如下:
1) 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;
2 )SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
3 )Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
4 )Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
5 ) Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

4 maven相关依赖

 <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.4.0</version>
    <type>pom</type>
 </dependency>
 <dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-core</artifactId>
	<version>${shiro-version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>${shiro.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>${shiro.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-quartz</artifactId>
    <version>${shiro.version}</version>
  </dependency>

5 Realm

在这里插入图片描述自定义realm一般继承 AuthorizingRealm(授权)即可,重写里面AuthenticationInfo 认证和doGetAuthorizationInfo授权方法。

6 用户登录demo

一、用户认证
1 Subject currentUser = SecurityUtils.getSubject();
2 UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray());
3 currentUser.login(token);

@Slf4j
@RestController
public class LoginController {

   @PostMapping("/login")
   @ResponseBody
   public Object loginPost(String username, String password) {
       
       if (StringUtils.isBlank(username)) {
           return renderError("用户名不能为空");
       }
       if (StringUtils.isBlank(password)) {
           return renderError("密码不能为空");
       }
       //Shiro加密
       // UserRealm userRealm = new UserRealm();
       // HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
       // matcher.setHashAlgorithmName("md5");//设置加密算法名称
       // matcher.setHashIterations(1);//设置加密的次数
       // userRealm.setCredentialsMatcher(matcher);
       Subject user = SecurityUtils.getSubject();
       UsernamePasswordToken token = new UsernamePasswordToken(username,password);
       Result result=new Result();
       try {
           //在这一步跳入入自己实现的域即shiroDbRealm中验证
           user.login(token);                                                                                                                                                            
           result.setMsg("登录成功");
           return result;
       } catch (UnknownAccountException e) {
       result.setMsg("账号不存在");
       return result;
       } catch (DisabledAccountException e) {
       result.setMsg("账号未启用");
       return result;
       } catch (IncorrectCredentialsException e) {
       result.setMsg("密码错误,请重试");
       return result;
       } catch (Throwable e) {
       result.setMsg("未知错误,请联系管理员");
       return result;
       }
      
   }
}

二、自定义Realm

@Slf4j
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private AuthorityService authorityService;

    /**
     * 权限认证
     * 取得当前用户权限
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //取得当前用户权限
        String permission= this.authorityService.getPermissionsForCurrentUser();
        Set<String> permissions = new HashSet<>();
        for(String element : permission.split(";")) {
            permissions.add(element);
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);
        return info;
    }

    /**
     * 登录认证
     * 验证用户输入到用户密码是否正确
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //第一种方式 获取用户的输入的账号.
        // UsernamePasswordToken mytoken=(UsernamePasswordToken) token;
        // String username=mytoken.getUsername();
        // String password = mytoken.getPassword().toString();

        //第二种  获取用户的输入的账号.
        String username = (String)token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        //根据用户名称查询数据库
        UserEntity userEntity = userService.queryUserByName(username);
        //账号不存在
        if(userEntity == null) {
            //用户不存在
			return null;
        }
        
        //如果能查询到,再由框架比对数据库中查询到的密码和页面提交的密码是否一致
        return new SimpleAuthenticationInfo(userEntity, password, getName());
    }
}

三、Shiro配置

@Configuration
@Slf4j
public class ShiroConfig {

	@Bean
	public FilterRegistrationBean delegatingFilterProxy(){
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
		DelegatingFilterProxy proxy = new DelegatingFilterProxy();
		proxy.setTargetFilterLifecycle(true);
		proxy.setTargetBeanName("shiroFilter");
		filterRegistrationBean.setFilter(proxy);
		return filterRegistrationBean;
	}

    /**
     * Shiro的过滤器链
     */
	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		/**
		 * 配置shiro拦截器链
		 * anon  不需要认证
		 * authc 需要认证
		 * 顺序从上到下,优先级依次降低
		 *
		 */
		Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
		filterChainDefinitionMap.put("/user/logind", "anon");
		filterChainDefinitionMap.put("/user/logoutd", "anon");
		filterChainDefinitionMap.put("/hive/sql", "anon");
		filterChainDefinitionMap.put("/cluster/host/services/**", "anon");
		filterChainDefinitionMap.put("/**.png", "anon");
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/**.js", "anon");
		filterChainDefinitionMap.put("/**.jpg", "anon");
		filterChainDefinitionMap.put("/**.less", "anon");
		filterChainDefinitionMap.put("/**.css", "anon");
		filterChainDefinitionMap.put("/index.html", "anon");
		filterChainDefinitionMap.put("/", "anon");
		filterChainDefinitionMap.put("/public/**", "anon");
		filterChainDefinitionMap.put("/**", "login");

		// 默认的登陆访问url,如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		shiroFilterFactoryBean.setLoginUrl("/unauth");
		//没有权限跳转的url
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

		shiroFilterFactoryBean.getFilters().put("login", new ShiroLoginFilter());
		shiroFilterFactoryBean.getFilters().put("perms", new ShiroPermsFilter());

		return shiroFilterFactoryBean;
	}


    /**
     * 项目自定义的Realm
     */
	@Bean
	public UserRealm myShiroRealm(){
		return new UserRealm();
	}


    /**
     * 安全管理器
     * @return
     */
	@Bean
	public SecurityManager securityManager(){
		DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
		securityManager.setRealm(myShiroRealm());
		securityManager.setCacheManager(ehCacheManager());
		securityManager.setSessionManager(sessionManager());
		return securityManager;
	}


	/**
	 * 设置session超时时间
	 * @return
	 */
	@Bean
	public SessionManager sessionManager(){
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setGlobalSessionTimeout(60*60*1000); //一个小时
		sessionManager.setSessionValidationSchedulerEnabled(true);
		sessionManager.setSessionIdUrlRewritingEnabled(false);
		return sessionManager;
	}
    /**
     * 记住密码Cookie
     * 新增
     */
    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setHttpOnly(true);
        simpleCookie.setMaxAge(7 * 24 * 60 * 60);//7天
        return simpleCookie;
    }

	/**
	 *  开启shiro aop注解支持.
	 *  使用代理方式;所以需要开启代码支持;
	 * @param
	 * @return
	 */

	@Bean
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
		DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		advisorAutoProxyCreator.setProxyTargetClass(true);
		return advisorAutoProxyCreator;
	}


	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
	
	/**
     * shiro缓存管理器
     *
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager(){
       log.info("ShiroConfig.getEhCacheManager()");
       EhCacheManager cacheManager = new EhCacheManager();
       //classpath:org/apache/shiro/cache/ehcache/ehcache.xml
       cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
       return cacheManager;
    }

}

7 Shiro常用的方法

得到 Subject 及创建用户名/密码身份验证 Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");

登录,即身份验证
subject.login(token);

判断用户是否经过验证
subject.isAuthenticated()

退出
subject.logout();

检查用户是否有admin 角色
subject.checkRole("role1")
subject.hasRole("role1")
subject.checkRoles("admin");
subject.hasAllRoles(Arrays.asList("role1", "role2"))

检查用户是否有user:delete权限
subject.isPermitted("user:create")
subject.isPermittedAll("user:update", "user:delete")
subject.checkPermission("user:create");  
subject.checkPermissions("user:delete", "user:update");  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

这个操蛋的人生!!!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值