SpringBoot整合shiro

shiro使用

介绍

简介

  1. Apache Shiro 是一个Java 的安全(权限)框架。
  2. Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环 境。
  3. Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等

关键对象

  1. Subject:任何可以与应用交互的 ‘用户’;
  2. Security Manager:相当于SpringMVC中的DispatcherServlet;是Shiro的心脏,所有具体的交互 都通过Security Manager进行控制,它管理者所有的Subject,且负责进行认证,授权,会话,及 缓存的管理。
  3. Authenticator:负责Subject认证,是一个扩展点,可以自定义实现;可以使用认证策略 (Authentication Strategy),即什么情况下算用户认证通过了;
  4. Authorizer:授权器,即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能 访问应用中的那些功能;
  5. Realm:可以有一个或者多个的realm,可以认为是安全实体数据源,即用于获取安全实体的,可 以用JDBC实现,也可以是内存实现等等,由用户提供;所以一般在应用中都需要实现自己的realm
  6. SessionManager:管理Session生命周期的组件,而Shiro并不仅仅可以用在Web环境,也可以用 在普通的JavaSE环境
  7. CacheManager:缓存控制器,来管理如用户,角色,权限等缓存的;因为这些数据基本上很少改 变,放到缓存中后可以提高访问的性能;
  8. Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于密码加密,解密等

实际运用

Springboot 整合使用shiro

引入相关依赖

相关依赖如下

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

配置shiro

shiro 主要需要配置一个过滤器 ShiroFilterFactoryBean,我们需要为ShiroFilterFactoryBean 配置拦截路径,安全管理器securityManager等

@Configuration
public class ShiroConfig {
	/**
	 * ShiroFilterFactoryBean 处理拦截资源文件问题。
	 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
	 * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
	 * 3、部分过滤器可指定参数,如perms,roles
	 */
	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		
		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		//访问的是后端url地址为 /login的接口
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 登录成功后要跳转的链接
		shiroFilterFactoryBean.setSuccessUrl("/index");
		// 未授权界面;
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		// 拦截器.
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/ajaxLogin", "anon");
		filterChainDefinitionMap.put("/userlogin", "anon");
		// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
		filterChainDefinitionMap.put("/logout", "logout");
        //配置某个url需要某个权限码
        filterChainDefinitionMap.put("/hello", "perms[how_are_you]");
 
		// 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 
		// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
		filterChainDefinitionMap.put("/", "user");  
		filterChainDefinitionMap.put("/**", "authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		System.out.println("Shiro拦截器工厂类注入成功");
		return shiroFilterFactoryBean;
	}
	
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 设置realm.
		securityManager.setRealm(myShiroRealm());
	}
	/**
	 * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
	 * @return
	 */
	@Bean
	public MyShiroRealm myShiroRealm() {
		MyShiroRealm myShiroRealm = new MyShiroRealm();
		return myShiroRealm;
	}
 
}

自定义ShiroRealm
继承AuthorizingRealm抽象类 主要实现两个方法 认证与授权

  1. 认证
    获取登录用户名username 使用username与数据库进行匹配 查询不到数据抛出UnknownAccountException 异常
    如果查询到数据则通过SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)进行认证
  2. 授权(并非每次调用接口都会执行授权方法 调用需要操作权限的接口才会执行认证方法)
    通过SecurityUtils.getSubject() 获取subject对象
    通过subject获取当前登录用户
    数据库查询用户所拥有的权限 并添加权限信息simpleAuthorInfo.addStringPermission(“user:add”);
public class MyRealm extends AuthorizingRealm{

    /*授权*/
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权=>AuthorizationInfo");
        /*给当前用户授权*/
        SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
        /*根据用户去数据库查询权限*/
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        System.out.println(user.toString());
        simpleAuthorInfo.addStringPermission("user:add");//给当前用户授权url为hello的权限码
        System.out.println("经试验:并不是每次调用接口就会执行,而是调用需要操作码(permission)的接口就会执行");
        return simpleAuthorInfo;
    }
    /*认证*/
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证=>AuthenticationInfo");
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        String username = usernamePasswordToken.getUsername();
        String password = new String(usernamePasswordToken.getPassword());
        /*System.out.println("-------" + usernamePasswordToken.getHost().toString()
        + usernamePasswordToken.getUsername() + usernamePasswordToken.getCredentials().toString()
        + usernamePasswordToken.getPrincipal() + usernamePasswordToken.getPassword().toString());*/

        /*从数据库中获取用户账号密码*/
        User user = new User("1","root","123456","2");

//        char[] password = usernamePasswordToken.getPassword();
        /*根据账号去数据库中查找记录*/
        /*为空返回账号不存在错误*/
        if(!username.equals("root")){
            throw new UnknownAccountException("账号不存在");
        }

        /*不为空 验证密码*/
            return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

登录退出

  1. 登录
    登录时首先封装用户的账号密码信息到UsernamePasswordToken,然后调用subject.login(UsernamePasswordToken) 无异常则登录成功
    public String login(String username,String password,Model model){
    //获取当前的用户
    Subject subject = SecurityUtils.getSubject();
    //封装用户的登录数据
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    try {
        subject.login(token);//执行登录方法,如果没有异常就说明OK
        return "index";
    } catch (UnknownAccountException e){//用户名不存在
        model.addAttribute("msg","用户名错误");
        return "login";
    }  catch (IncorrectCredentialsException e){//密码不存在
        model.addAttribute("msg","密码错误");
        return "login";
    }
}
  1. 注销用户
public String logout(){
    /*subject的实现类DelegatingSubject的logout方法,将本subject对象的session清空了
	即使session托管给了redis ,redis有很多个浏览器的session
	只要调用退出方法,此subject的、此浏览器的session就没了*/
    SecurityUtils.getSubject().logout();
    return "login";
}

获取当前登录用户

SecurityUtils.getSubject().getPrincipal();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值