这是shiro入门的第二篇文章,第一篇文(Post not found: Spring Boot集成shiro步骤 Spring Boot集成shiro步骤 )章使用的还是比较老的shiro-spring依赖,这一篇,使用了shiro-spring-boot-web-starter,写法和思路还是有些差别的。
参考文章:
1.
SpringSecurity能否吊打Shiro? 如果开发的项目是Spring这一套,用Spring Security我觉得更合适一些,他们本身就是一套东西,顺畅,可能略微复杂一些,但是学会了就是自己的。如果开发项目比较紧张,Shiro可能更合适,容易上手,也足够用,Spring Security中有的,Shiro也基本都有,没有的部分网上也有大批的解决方案。如果项目没有使用Spring这一套,不用考虑,直接Shiro。同时要考虑团队成员的技术栈,更加熟悉使用哪个,在选型上,也要尽量避免给同行增加不必要的学习成本!
1.引入依赖
org.apache.shiro
shiro-spring-boot-web-starter
1.5.3
1 2 3 4 5 6 7 8 9 ## 2.提供一个Realm实现 比如我的 ``` java @Bean public Realm realm() { DatabaseRealm databaseRealm=new DatabaseRealm(); return databaseRealm; }
其中DatabaseRealm代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 import com.proheng.gis.Entity.UserInfo;import com.proheng.gis.Reposities.UserInfoRepository;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;public class DatabaseRealm extends AuthorizingRealm { private final Logger logger = LoggerFactory.getLogger(this .getClass()); @Autowired private UserInfoRepository userInfoService; @Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); UserInfo userInfo = userInfoService.findByUsername(username); if (userInfo == null ){ return null ; } try { SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo ( userInfo.getUsername(), userInfo.getPassword(), getName() ); authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userInfo.getCredentialsSalt())); return authenticationInfo; }catch (Exception e){ System.out.println("授权失败" ); logger.error("doGetAuthenticationInfo" ,userInfo); return null ; } } @Override protected AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo (); return authorizationInfo; } }
3.定义一个ShiroFilterChainDefinition 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition () { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition (); chainDefinition.addPathDefinition("/admin/**" , "authc, roles[admin]" ); chainDefinition.addPathDefinition("/docs/**" , "authc, perms[document:read]" ); chainDefinition.addPathDefinition("/**" , "authc" ); return chainDefinition; }
简直太简单了有没有?下面的步骤,可以做,也可以不做,都没有关系的,反正上面三步就已经完成了大部分的内容,下面的只是根据需要做一些完善。
4.配置过滤器 配置过滤器,在完成了上面的几个步骤的时候,如果还要进一步的做一些其他的东西,比如设置未登录的跳转页面,在拦截ajax请求的时候,返回json字符串,而不是一个login.jsp页面,就需要配置过滤器了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean (SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean (); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, Filter> filters = shiroFilterFactoryBean.getFilters(); shiroFilterFactoryBean.setLoginUrl("/" ); shiroFilterFactoryBean.setSuccessUrl("/index" ); shiroFilterFactoryBean.setUnauthorizedUrl("/403" ); return shiroFilterFactoryBean; }
注意 过滤器的名字不能是shiroFilter而必须是shiroFilterFactoryBean,否则启动的时候就会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Bean public ShiroFilterFactoryBean shiroFilter (SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean (); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, Filter> filters = shiroFilterFactoryBean.getFilters(); shiroFilterFactoryBean.setLoginUrl("/" ); shiroFilterFactoryBean.setSuccessUrl("/index" ); shiroFilterFactoryBean.setUnauthorizedUrl("/403" ); Map<String, String> filterChainDefinitionMap = new LinkedHashMap <String, String>(); filterChainDefinitionMap.put("/**" , "authc" ); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; }
关于x-requested-with的作用以及用法详解 很多的时候,都是在写Shiro的时候,会出现一个判断请求是否是ajax请求的功能,通过自定义Filter,判断如果请求是Ajax请求,就返回一个json字符串,如果不是ajax请求,就直接返回一个页面。大部分的说明都是请求头中是否携带x-requested-with选项作为是否是ajax的请求,但是这个选项只是jquery等前端库自己添加的,并不是标准的请求头,所以有时候通过这个请求头并不能判断这是一个ajax请求,比如原生的XMLHTTPRequest,比如fetch等,都没有这个请求头。所以在判断是否是ajax请求的时候,还是选择其他的方式吧。