非starter方式实现springboot与shiro集成

6 篇文章 0 订阅
3 篇文章 0 订阅

Apache Shiro是什么?

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

Apache Shiro的主要API

Subject

Subject即“当前操作用户”。但是,在Shiro中,Subject这一概念并不是"帐户",而是与shrio交互的当前应用。

SecurityManager

SecurityManager是Shiro框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

Realm

  • Realm是安全数据源,其中包含认证和授权数据。

    也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

  • 当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。

    Shiro内置了很多可用的安全数据源(又名目录)的Realm, 如果内置的Realm不能满足需求,可以自定义Realm实现。

Apache Shiro与Springboot集成

依赖引入

	<!-- Shiro核心包 -->
	<dependency>
		<groupId>org.apache.shiro</groupId>
		<artifactId>shiro-core</artifactId>
		<version>1.4.1</version>
	</dependency>
	
	<!-- Shiro Web支持包 -->
	<dependency>
	    <groupId>org.apache.shiro</groupId>
	    <artifactId>shiro-web</artifactId>
	    <version>1.4.1</version>
	</dependency>
	
	<!-- Shiro与Spring的集成包 -->
	<dependency>
	    <groupId>org.apache.shiro</groupId>
	    <artifactId>shiro-spring</artifactId>
	    <version>1.4.1</version>
	</dependency>

开发集成shiro的配置类

开发一个集成shiro的spring配置类

@Configuration
public class ShiroConfigure {
	private static final Logger LOG = LoggerFactory.getLogger(ShiroConfigure.class);    
	
	//注册跨域过滤器
	//开发和配置安全数据源
	//配置Shiro安全管理器
	//配置shiro过滤器拦截规则定义
	//配置shiro过滤器
	//配置shiro生命周期管理器
	
}

注册跨域过滤器

shiro过滤器会优先于springboot拦截请求,springboot的跨域设置将不起作用,因此需要专门注册跨域过滤器并设置其为过滤器链中的第一个。

 	@Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        
    	final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        
    	final CorsConfiguration config = new CorsConfiguration();
    	
        // 允许cookies跨域
        config.setAllowCredentials(true);
        
        // 允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedOrigin("*");
        
        // 允许访问的头信息,*表示全部
        config.addAllowedHeader("*");
        
        // 预检请求(options请求)的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.setMaxAge(1L);
        
        // 允许提交请求的方法,*表示全部允许
        config.addAllowedMethod("*");
        /*
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        */
        
        //设置允许跨域的路径
        source.registerCorsConfiguration("/**", config);

        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
        
        // 设过滤器的优先级
        bean.setOrder(0);

        return bean;
    }

开发和配置安全数据源

   /*
    *   配置安全数据源Realm
    *   此处必须要命名“authorizer”,
    *   因为shiro会自动寻找名称为“authorizer”的、并实现接口Authorizer的对象,
    *   而AuthorizingRealm正是接口Authorizer的实现类
    */
    @Bean("authorizer")
    @Autowired
    public AuthorizingRealm saftyRealm(ShiroService shiroService) {
        
        return new AuthorizingRealm() {

            /**
            * 获取当事人(当前用户)授权信息,shiro在检查访问是否经过授权时需要通过该方法获取授权信息。
            * 参数PrincipalCollection 当事人集合
            */	
            @Override
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

                /*
                * 获取登录用户帐号
                */
                CurrUser currUser = (CurrUser) principalCollection.getPrimaryPrincipal();// 获取首要(第一)当事人

                /*
                * 创建授权信息对象
                */
                SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

                
                        
                /*
                * 查询用户权限,并将权限放入授权信息对象中		 
                */
                List<Module> moduleList = shiroService.getModulesOfUser(currUser.getUserId());
                for (Module module : moduleList) {
                    simpleAuthorizationInfo.addStringPermission(String.valueOf(module.getM_id()));
                }

                // System.out.println(currUser.getUserId()+"->"+simpleAuthorizationInfo.getStringPermissions());

                /*
                * 返回授权信息
                */
                return simpleAuthorizationInfo;
            }

            /**
            * 获取认证信息(即包含当前用户帐户和合法密码等信息)
            * shiro在登录认证时需要通过该方法获取认证信息。
            * 参数 AuthenticationToken 认证令牌(如:一组用户名和密码就是一个认证令牌)
            */
            @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)  {

                String userId = (String) token.getPrincipal();// 获得当事人(当前用户账号)

                User user = shiroService.getUser(userId);

                /*
              		如果不存在前用户信息,返回null
                */
                if (user == null) {
                    return null;
                }

                /*
                	创建当前用户
                */
                CurrUser currUser = new CurrUser(user.getU_id(),user.getU_name());
                
                
                /*
                	创建认证信息,三个构造参数含义依次如下:
                	参数1:principal当前用户 
               		参数2:credentials认证凭证(如:口令、密码等)
         			参数3:realm名称
                */
                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currUser, user.getU_pwd(), this.getName());

                /*
                	返回认证信息
                */
                return info;
            }
            
        } ;
    }

配置Shiro安全管理器

    @Bean 
    @Autowired
    public org.apache.shiro.mgt.SecurityManager shiroSecurityManager(Realm realm) {
    	DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    	securityManager.setRealm(realm);
    	return securityManager;
    }

配置shiro过滤器拦截规则定义

    @Bean @Autowired
    public ShiroFilterChainDefinition shiroFilterChainDefinition(ShiroService shiroService) {
        
        DefaultShiroFilterChainDefinition chainDefinition = 
                                                    new DefaultShiroFilterChainDefinition();
        
    
        /*
            可匿名访问资源
        */
        chainDefinition.addPathDefinition("/css/**", "anon");
        chainDefinition.addPathDefinition("/elementui/**", "anon");
        chainDefinition.addPathDefinition("/js/**", "anon");
        chainDefinition.addPathDefinition("/safty/login/**", "anon");
        
        
        //加载动态权限 
        List<Module> moduleList = shiroService.getAllSubModules();
        
        String PREMISSION_FORMAT = "authc,perms[{0}]";
        
        //动态权限设置
        for(Module module:moduleList) {
            
        	if(StringUtils.isEmpty(module.getM_url())) {
                continue;
            }
            
            
            chainDefinition.addPathDefinition(module.getM_url().replace("index.html", "**"), MessageFormat.format(PREMISSION_FORMAT, String.valueOf(module.getM_id())));
            
            
        }
        
        //其它资源必须经过认证
        chainDefinition.addPathDefinition("/**", "authc");
        
        LOG.debug("=====Shiro安全规则=======================================================================");
        LOG.debug(chainDefinition.getFilterChainMap().toString());
        LOG.debug("=====Shiro安全规则=======================================================================");
        
        return chainDefinition;
    }
    
}

配置shiro过滤器

    @Bean
    @Autowired
    public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager,ShiroFilterChainDefinition shiroFilterChainDefinition) throws Exception {
    
    	ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    	
    	shiroFilterFactoryBean.setSecurityManager(securityManager);

		//设置登录url,shiro发现未认证时自动重定向到该url,如果是前后端分离式开发该url应当发送json串。
    	shiroFilterFactoryBean.setLoginUrl("/loginTo");
    	
    	//设置未授权url,shiro发现未授权时自动重定向到该url,如果是前后端分离式开发该url应当发送json串。
    	shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedTo");
    	
    	shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
    
    	return shiroFilterFactoryBean;
    
    }

配置shiro生命周期管理器

    @Bean
    public org.apache.shiro.spring.LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
    	return new org.apache.shiro.spring.LifecycleBeanPostProcessor();
    }

登录示例

@RestController
@RequestMapping("/safty/login")
public class LoginController {
	
	@Autowired
	private LoginService loginService;
	
	@PostMapping("/user")
	public Result execLogin(@RequestBody UserDto userDto,HttpSession session) {

		try {
			Subject subject = SecurityUtils.getSubject();
			
			//创建登录令牌
			UsernamePasswordToken usernamePasswordToken = 
					new UsernamePasswordToken(userDto.getU_id(),userDto.getU_pwd());
			
			//登录,该方法声明抛出异常,可以捕获异常,并进行应对处理
			subject.login(usernamePasswordToken);
			
			//是否通过认证
			if(subject.isAuthenticated()) {
				
				//获得当前用户信息
				CurrUser currUser = (CurrUser)subject.getPrincipal();
				
				//将当前用户放入Session。注:这里的Session是由Shiro提供的。
				subject.getSession().setAttribute(Constants.SESSINON_ATTR_NAME_CURR_USER, currUser);
				
				
				return Result.successResult("登录成功!");
			}
			
			return Result.failResult("登录失败!");
			
		} catch (UnknownAccountException e) {
			return Result.failResult("用户名不存在!");
	    	
	    } catch (IncorrectCredentialsException e) {
	    	return Result.failResult("账户密码不正确!");
	    } catch (LockedAccountException e) {
	    	return Result.failResult("用户名被锁定 !");
	    }catch (Exception e) {
			e.printStackTrace();
			return Result.failResult("系统错误!");
		}
		
	}

}

退出示例

@RestController
@RequestMapping("/safty/logout")
public class LoginController {
	
	@Autowired
	private LoginService loginService;
		
	@DeleteMapping("/logout")
	public ResultDto login_authentication() {
		
		try {
			//注销
			SecurityUtils.getSubject().logout();
			return Result.successResult();
		} catch (Exception e) {
			return Result.failResult("退出失败!");
		}
	}
}

测试

上述配置和相关代码开发完成后,即可进行测试调试。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值