Spring Boot系列 安全框架Apache Shiro基本功能.docx

上传人:牧羊曲112 文档编号:3166016 上传时间:2023-03-11 格式:DOCX 页数:17 大小:43.10KB
返回 下载 相关 举报
Spring Boot系列 安全框架Apache Shiro基本功能.docx_第1页
第1页 / 共17页
Spring Boot系列 安全框架Apache Shiro基本功能.docx_第2页
第2页 / 共17页
Spring Boot系列 安全框架Apache Shiro基本功能.docx_第3页
第3页 / 共17页
Spring Boot系列 安全框架Apache Shiro基本功能.docx_第4页
第4页 / 共17页
Spring Boot系列 安全框架Apache Shiro基本功能.docx_第5页
第5页 / 共17页
亲,该文档总共17页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《Spring Boot系列 安全框架Apache Shiro基本功能.docx》由会员分享,可在线阅读,更多相关《Spring Boot系列 安全框架Apache Shiro基本功能.docx(17页珍藏版)》请在三一办公上搜索。

1、Spring Boot系列 安全框架Apache Shiro基本功能Spring Boot系列 安全框架Apache Shiro基本功能 Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。 详细基础知识,请参考跟我学Shiro 的系列文章 这里只是给出Spring Boot 集成Shiro 的案例,Spring Boot就是为了简化传统Spring开发的复杂度,即

2、去xml化,所以案例中也是没有xml配置,完全 javaconfig方式配置。 集成Shiro核心内容: ShiroFilterFactory,Shiro过滤器工程类,具体的实现类是:ShiroFilterFactoryBean,此实现类是依赖于SecurityManager安全管理器。主要配置Filter就好。 SecurityManager,Shiro的安全管理,主要是身份认证的管理,缓存管理,cookie管理,所以在实际开发中我们主要是和SecurityManager进行打交道的。 Realm,用于身份信息权限信息的验证。开发时集成AuthorizingRealm,重写两个方法:doGe

3、tAuthenticationInfo(获取即将需要认真的信息)、doGetAuthorizationInfo(获取通过认证后的权限信息)。 HashedCredentialsMatcher,凭证匹配器,用于告诉Shiro在认证时通过什么方式(算法)来匹配密码。默认(storedCredentialsHexEncoded=false)Base64编码,可以修改为(storedCredentialsHexEncoded=true)Hex编码。 LifecycleBeanPostProcessor,Shiro生命周期处理器,保证实现了Shiro内部lifecycle函数的bean执行。 开启Shi

4、ro的注解功能(如RequiresRoles,RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证,需要配置两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)实现此功能。 其它的就是缓存管理,记住登录、验证码、分布式系统共享Session之类的,这些大部分都是需要自己进行的实现,其中缓存管理,记住登录比较简单实现,并需要注入到SecurityManager让Shiro的安全管理器进行管理就好了。后续章节中会一 一补充。 下

5、面使用Spring Boot 集成Shiro完成一个比较简单的安全验证: 步骤1:首先创建一个Maven工程,在pom.xml中添加shiro相关依赖包: org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.2.5 com.github.theborakompanioni thymeleaf-extras-shiro 1.2.1 目录结构图(其中RetryLimitHashedCredentialsMatcher.java在本例中为使用): 本案例的工程目录结构图 步骤2:

6、实现用户、角色的CRUD的相关类(domain,dao/mapper/repository,service),由于篇幅和重要点关系,这些就省略了。 步骤3:实现Realm,继承AuthorizingRealm,并重写doGetAuthorizationInfo(用于获取认证成功后的角色、权限等信息) 和 doGetAuthenticationInfo(验证当前登录的Subject)方法 public class UserRealm extends AuthorizingRealm Resource private UserService userService; Resource privat

7、e RoleService roleService; Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) String currentLoginName = (String)principals.getPrimaryPrincipal; List userRoles = new ArrayList; List userPermissions = new ArrayList; /从数据库中获取当前登录用户的详细信息 User user = userService.f

8、indByLoginName(currentLoginName); if(null != user) /获取当前用户下所有ACL权限列表 待续。 /获取当前用户下拥有的所有角色列表 List roles = roleService.findByUserId(user.getId); for (int i = 0; i roles.size; i+) userRoles.add(roles.get(i).getCode); else throw new AuthorizationException; System.out.println(#获取角色:+userRoles); System.out

9、.println(#获取权限:+userPermissions); /为当前用户设置角色和权限 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo; authorizationInfo.addRoles(userRoles); authorizationInfo.addStringPermissions(userPermissions); return authorizationInfo; /* * 验证当前登录的Subject * LoginController.login方法中执行Subject.l

10、ogin时 执行此方法 */ Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException System.out.println(#+SecurityUtils.getSubject.getSession.getId); String loginName = (String)authcToken.getPrincipal; User user = userService.findByLoginName(lo

11、ginName); if(user = null) throw new UnknownAccountException;/没找到帐号 /交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user.getUserName, /用户名 user.getPassword, /密码 ByteSource.Util.bytes(user.getCredentialsSalt)

12、,/salt=username+salt,采用明文访问时,不需要此句 getName /realm name ); return authenticationInfo; 步骤4:创建Shiro配置类:ShiroConfiguration,这是最重要的,用于替代XML配置的Java Config,详细说明,请看代码中注释。 Configuration public class ShiroConfiguration private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class); /* *

13、 Shiro的Web过滤器Factory 命名:shiroFilter * * param securityManager * return */ Bean(name = shiroFilter) public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) logger.info(注入Shiro的Web过滤器-shiroFilter, ShiroFilterFactoryBean.class); ShiroFilterFactoryBean shiroFilterFactoryBea

14、n = new ShiroFilterFactoryBean; /Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); /要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的/login.jsp页面 shiroFilterFactoryBean.setLoginUrl(/login); /登录成功后要跳转的连接,逻辑也可以自定义,例如返回上次请求的页面 shiroFilterFactoryBean.setSuccessUrl(/index);

15、 /用户访问未对其授权的资源时,所显示的连接 shiroFilterFactoryBean.setUnauthorizedUrl(/pages/403); /*定义shiro过滤器,例如实现自定义的FormAuthenticationFilter,需要继承FormAuthenticationFilter *本例中暂不自定义实现,在下一节实现验证码的例子中体现 */ /*定义shiro过滤链 Map结构 * Map中key(xml中是指value值)的第一个/代表的路径是相对于HttpServletRequest.getContextPath的值来的 * anon:它对应的过滤器里面是空的,什么

16、都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 * authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter */ Map filterChainDefinitionMap = new LinkedHashMap; / 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put(/logout, logout); / :这是一个坑呢,一不小心代码就不好使了;

17、/ filterChainDefinitionMap.put(/webui/*, anon); filterChainDefinitionMap.put(/webjars/*, anon); filterChainDefinitionMap.put(/login, anon); filterChainDefinitionMap.put(/*, authc); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; /* * 不指定名字

18、的话,自动创建一个方法名第一个字母小写的bean * Bean(name = securityManager) * return */ Bean public SecurityManager securityManager logger.info(注入Shiro的Web过滤器-securityManager, ShiroFilterFactoryBean.class); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager; securityManager.setRealm(userRealm); r

19、eturn securityManager; /* * Shiro Realm 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的 * * param cacheManager * return */ Bean public UserRealm userRealm UserRealm userRealm = new UserRealm; /告诉realm,使用credentialsMatcher加密算法类来验证密文 userRealm.setCredentialsMatcher(hashedCredentialsMatcher); userRe

20、alm.setCachingEnabled(false); return userRealm; /* * 凭证匹配器 * * 可以扩展凭证匹配器,实现 输入密码错误次数后锁定等功能,下一次 * return */ Bean(name=credentialsMatcher) public HashedCredentialsMatcher hashedCredentialsMatcher HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher; hashedCredentialsMatcher

21、.setHashAlgorithmName(md5);/散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(2);/散列的次数,比如散列两次,相当于 md5(md5(); /storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码 hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true); return hashedCredentialsMatcher; /* * Shiro生命周期处

22、理器 * return */ Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor return new LifecycleBeanPostProcessor; /* * 开启Shiro的注解(如RequiresRoles,RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现

23、此功能 * return */ Bean DependsOn(lifecycleBeanPostProcessor) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator; advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; Bea

24、n public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor; authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSo

25、urceAdvisor; /* * 添加ShiroDialect 为了在thymeleaf里使用shiro的标签的bean * return */ Bean(name = shiroDialect) public ShiroDialect shiroDialect return new ShiroDialect; 步骤四5:实现Controller,登录/退出等操作。 Controller public class SecurityController private static final Logger logger = LoggerFactory.getLogger(UserContro

26、ller.class); RequiresRoles(ADMIN) RequestMapping(value=/index,method=RequestMethod.GET) public String index(Model model) String userName = (String) SecurityUtils.getSubject.getPrincipal; model.addAttribute(username, userName); return index; RequestMapping(value=,method=RequestMethod.GET) public Stri

27、ng defaultIndex(Model model) String userName = (String) SecurityUtils.getSubject.getPrincipal; model.addAttribute(username, userName); return index; RequestMapping(value=/login,method=RequestMethod.GET) public String loginForm(Model model) model.addAttribute(user, new User); return login; RequestMap

28、ping(value=/login,method=RequestMethod.POST) public String login(Valid User user,BindingResult bindingResult,RedirectAttributes redirectAttributes) if(bindingResult.hasErrors) return login; String username = user.getUserName; System.out.println(username); UsernamePasswordToken token = new UsernamePa

29、sswordToken(user.getUserName, user.getPassword); /获取当前的Subject Subject currentUser = SecurityUtils.getSubject; try /在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查 /每个Realm都能在必要时对提交的AuthenticationTokens作出反应 /所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo方法中,具

30、体验证方式详见此方法 logger.info(对用户 + username + 进行登录验证.验证开始); currentUser.login(token); logger.info(对用户 + username + 进行登录验证.验证通过); catch(UnknownAccountException uae) logger.info(对用户 + username + 进行登录验证.验证未通过,未知账户); redirectAttributes.addFlashAttribute(message, 未知账户); catch(IncorrectCredentialsException ice)

31、 logger.info(对用户 + username + 进行登录验证.验证未通过,错误的凭证); redirectAttributes.addFlashAttribute(message, 密码不正确); catch(LockedAccountException lae) logger.info(对用户 + username + 进行登录验证.验证未通过,账户已锁定); redirectAttributes.addFlashAttribute(message, 账户已锁定); catch(ExcessiveAttemptsException eae) logger.info(对用户 + u

32、sername + 进行登录验证.验证未通过,错误次数过多); redirectAttributes.addFlashAttribute(message, 用户名或密码错误次数过多); catch(AuthenticationException ae) /通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景 logger.info(对用户 + username + 进行登录验证.验证未通过,堆栈轨迹如下); ae.printStackTrace; redirectAttributes.addFlashAttribute(message

33、, 用户名或密码不正确); /验证是否登录成功 if(currentUser.isAuthenticated) logger.info(用户 + username + 登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作); return /index; else token.clear; return redirect:/login; RequestMapping(value=/logout,method=RequestMethod.GET) public String logout(RedirectAttributes redirectAttributes ) /使用权限管理工

34、具进行用户的退出,跳出登录,给出提示信息 SecurityUtils.getSubject.logout; redirectAttributes.addFlashAttribute(message, 您已安全退出); return redirect:/login; RequestMapping(/pages/403) public String unauthorizedRole logger.info(-没有权限-); return pages/403; 步骤6:前端页面,采用Thymeleaf引擎 login.html: 用户登录 body margin-left:auto; margin-right:auto; margin-TOP:100PX; width:20em; 登 录 index.html: 首页 Hello, , how are you today? Im fine, 我拥有管理员角色- 403.html: Insert title here

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号