文章目录

  • 前言
  • 一、登录
  • 二、配置ShiroConfig
    • 1.编写ShiroConfig
    • 2.身份认证过滤器
    • 3.Shiro域
  • 三、测试

前言

现在大部分web应用都是使用前后端分离的架构开发,这就需要通过token做为前端访问后端接口时的身份标识。前端在访问登录接口时,登陆成功给前端返回一个token值,前端可以通过这个token值来访问被赋予权限的接口。


一、登录

登录接口如下所示,在登录阶段,把用户输入的用户名和密码信息与后端数据库中所存储的信息进行比对,如果比对成功且符合登录条件,后端将会产生一个token给前端。

    @GetMapping("/login")public ResponseVo login(String username, String password){if(StringUtils.isEmpty(username)){return ResponseVo.error("未输入用户名");}SysUserEntity user=sysUserService.findByUserName(username);if(user==null||!user.getPassword().equals(new Sha256Hash(password, user.getSalt()).toHex())){return ResponseVo.error("用户不存在或密码不正确");}if(user.getStatus()==0){return ResponseVo.error("用户已锁定,请联系管理员");}ResponseVo responseVo=sysUserTokenService.createToken(user.getUserId());return responseVo;}

二、配置ShiroConfig

1.编写ShiroConfig

ShiroConfig是shiro的配置类,在配置类中配置了安全管理器,shiro过滤器,生命周期后置处理器、授权资源通知器和默认通知器代理生成器。
1、AuthorizationAttributeSourceAdvisor和DefaultAdvisorAutoProxyCreator的配置是为了开启shiro注解(例如@RequiredPermissions、@RequiredRoles等)。
2、LifecycleBeanPostProcessor是用来管理shiro的生命周期。
3、shiro过滤器主要是来判定哪些接口需要认证,哪些接口可以匿名访问,由于使用了token方式,所以需要编写一个适用于token方式认证的过滤器。
4、SecurityManager做为shiro框架中的安全管理器,主要需要注入shiroRealm属性,来实现身份认证功能和授权功能。

@Configuration
public class ShiroConfig {@Beanpublic SecurityManager securityManager(ShiroRealm shiroRealm){DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(shiroRealm);defaultWebSecurityManager.setRememberMeManager(null);return defaultWebSecurityManager;}@Beanpublic ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);HashMap<String,Filter> map=new HashMap();map.put("oauth2",new AuthenticFilter());shiroFilterFactoryBean.setFilters(map);HashMap<String,String> filter=new HashMap();filter.put("/kaptcha.jpg","anon");filter.put("/login","anon");filter.put("/webjars/**","anon");filter.put("/swagger/**","anon");filter.put("/v2/api-docs", "anon");filter.put("/swagger-ui.html", "anon");filter.put("/swagger-resources/**", "anon");filter.put("/**","oauth2");shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);return shiroFilterFactoryBean;}@Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){return new LifecycleBeanPostProcessor();}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager);return advisor;}@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();autoProxyCreator.setProxyTargetClass(true);return autoProxyCreator;}
}

2.身份认证过滤器

上一小节提到,使用token方式登录需要自己编写接口的过滤器。该过滤器中一共重写了四个方法,分别是createToken、onAccessDenied、onLoginFailure和isAccessAllowed。
1、createToken是为了在后续的登录流程中产生一个AuthenticationToken对象,而这个对象是在前端请求时在Header或者Parameter中携带的(也就是在登录成功时,后端返回给前端的)。
2、onAccessDenied是拿到前端携带的token之后,进行shiro后续的身份认证流程。
3、onLoginFailure是在身份认证失败后进行的流程。
4、isAccessAllowed是允许不经过过滤器的条件。

public class AuthenticFilter extends AuthenticatingFilter {public final static String TOKEN="token";@Overrideprotected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {String token=getRequestToken((HttpServletRequest) request);if(StringUtils.isBlank(token)){return null;}return new AuthenticToken(token);}@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {String token=getRequestToken((HttpServletRequest) request);if(StringUtils.isBlank(token)){HttpServletResponse httpReponse= (HttpServletResponse) response;httpReponse.setHeader("Access-Control-Allow-Credentials","true");httpReponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getHeader("Origin"));httpReponse.getWriter().print(JSON.toJSONString(ResponseVo.error(HttpStatus.SC_UNAUTHORIZED,"invalid token")));return false;}return executeLogin(request,response);}@Overrideprotected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {HttpServletResponse httpResponse= (HttpServletResponse) response;httpResponse.setContentType("application/json;charset=utf-8");httpResponse.setHeader("Access-Control-Allow-Credentials", "true");httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getHeader("Origin"));try {Throwable throwable=e.getCause();//throwable.getMessage()ResponseVo responseVo=ResponseVo.error(HttpStatus.SC_UNAUTHORIZED,null);httpResponse.getWriter().print(JSON.toJSON(responseVo));} catch (IOException e1) {e1.printStackTrace();}return false;}@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {if(RequestMethod.OPTIONS.name().equals(((HttpServletRequest) request).getMethod())){return true;}return false;}private String getRequestToken(HttpServletRequest request){String token=request.getHeader(TOKEN);if(StringUtils.isBlank(token)){token=request.getParameter(TOKEN);}return token;}
}

3.Shiro域

ShiroRealm重写了父类三个方法,分别是supports、doGetAuthorizationInfo和doGetAuthenticationInfo。
1、supports方法是为了让realm可以支持我们所自定义的token。在shiro框架登录的源码中,会对我们所传入的token进行判断,如果我们未重写该方法,那么登录将会失败。

2、doGetAuthenticationInfo,该方法是用来存储登录用户的身份认证信息。前端在登录成功后拿到后端返回的token。然后带着这个token去访问需要权限的接口时,会先经过shiro框架内部的登录流程,而登录流程的最终步骤就是调用doGetAuthenticationInfo这个方法,产生一个AuthenticationInfo类型的对象存储到当前的后台线程中,以供后续的授权服务使用。
3、doGetAuthorizationInfo,该方法是来存储用户的所拥有的授权信息。当前端所调用的方法上遇到@RequiredPermissions注解时,shiro框架就会根据我们通过该方法创建的AuthorizationInfo对象中去寻找登录用户是否拥有该权限。该方法的内容比较简单,就是通过doGetAuthenticationInfo产生的AuthenticationInfo类型的对象中的user信息从数据库中的role表中查出相对应的角色,然后拿着角色信息去权限表中查出所拥有的权限存储到AuthorizationInfo类型的对象中。

@Component
public class ShiroRealm extends AuthorizingRealm {@Autowiredprivate SysUserTokenRepository sysUserTokenRepository;@Autowiredprivate SysUserRepository sysUserRepository;@Autowiredprivate SysPermissionRepository sysPermissionRepository;//realm必须支持接受token@Overridepublic boolean supports(AuthenticationToken token) {return token instanceof AuthenticToken;}@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();SysUserEntity user= (SysUserEntity) principals.getPrimaryPrincipal();Set<String> permissionSet=new HashSet<>();List<String> list=sysPermissionRepository.getPermsByUserId(user.getUserId());for(String perms:list){if(StringUtils.isBlank(perms)){continue;}permissionSet.addAll(Arrays.asList(perms.trim().split(",")));}authorizationInfo.setStringPermissions(permissionSet);return authorizationInfo;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String accessToken= (String) token.getPrincipal();Optional<SysUserTokenEntity> userTokenOpt=sysUserTokenRepository.getSysUserTokenEntitiesByToken(accessToken);if(!userTokenOpt.isPresent()){throw new IncorrectCredentialsException("token不存在");}SysUserTokenEntity userToken=userTokenOpt.get();if(userToken.getExpireTime().getTime()<System.currentTimeMillis()){throw new IncorrectCredentialsException("token已经失效");}SysUserEntity user=sysUserRepository.getById(userToken.getUserId());SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(user,accessToken,getName());return authenticationInfo;}
}

三、测试

1.调用/login方法进行登录操作,后端返回token。

2.将该token放入请求的Header中,去访问/createUser接口(该登录用户拥有sys:user:save权限)

3.测试结果

如何前后端分离的架构中使用Shiro框架相关推荐

  1. 前后端分离 MVC 架构与 Java 接口规范,深入剖析必要性!

    >>号外:关注"Java精选"公众号,回复"面试资料",免费领取资料!"Java精选面试题"小程序,3000+ 道面试题在线刷, ...

  2. 若依前后端分离版(vue)中配置页面跳转的路由

    场景 若依前后端分离版本地搭建开发环境并运行项目的教程: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662 在此基 ...

  3. Python Web开发(六):前后端分离的架构

    本文目录: 一.代码直接生成HTML 二.使用模板 三.前后端分离架构 `[系列好文推荐]` 前言:

  4. Java微服务前后端分离技术开发的微信快速框架-教程

    JooLun微信快速开发框架-采用目前最流行的前后端分离框架开发出来的微信快速开发平台.二次开发效率高,技术先进不怕被淘汰 系统特性: Spring Cloud微服务化开发,采用Nacos注册和配置中 ...

  5. 分享两款智慧物业系统源码,前后端分离,前端VUE,Uni-app框架

    分享两款智慧物业管理系统源码,源码免费分享,需要源码学习参考的小伙伴可以私信我. ▶▶▶1:Java智慧物业管理系统源码(App+业主端微信小程序+物业端H5) 智慧物业介绍: 一.技术架构 基于Sp ...

  6. 前后端分离技术架构模式演变

    PHP与Vite能摩擦出啥样的爱情火花? 一.背景 前段日子公司里准备要重构一个拥有10年高龄的网站,当时听到这个消息心里无比激动,因为我现在就是这个网站的维护人员

  7. 若依前后端分离如何写移动端接口_前后端分离实践的架构设计

    前后端分离的项目开发策略已经不是什么新鲜东西了,网上介绍这方面的文章非常多.我自己是在14年的时候接触到的,对这种开发策略一直爱不释手,不管新老项目都会首先用前后端分离的思维先去思考一番.从14年到现 ...

  8. 前后端分离架构一直没机会实战?1周完成Vue+Core WebApi移动商城实战(含源码)!...

    疫情让企业受到重创! 就业形势更加严峻! 前后端分离架构成了当下最高频的招聘需求 还没实战过前后端分离? 花3分钟阅读本文, 带你全面了解前后端分离,轻松面试拿高薪! Web发展至今技术非常成熟,主流 ...

  9. 前后端分离中的权限管理思路

    在传统的前后端不分的开发中,权限管理主要通过过滤器或者拦截器来进行(权限管理框架本身也是通过过滤器来实现功能),如果用户不具备某一个角色或者某一个权限,则无法访问某一个页面. 但是在前后端分离中,页面 ...

  10. Hybris平台Web架构模式演变:前后端分离

    "前后端分离"显然已不是什么新鲜的话题,表面上看是一场架构模式的变革,但实质上是为了解决以往传统的服务端MVC设计模式的一些诟病和痛点.前后端分离带来的全新的前后端协作方式能够让专 ...

最新文章

  1. java-结合c3p0封装的db 事务 类
  2. Android动画效果 translate、scale、alpha、rotate 切换Activity动画 控件位置调整
  3. 在 Oracle 和 PHP 中使用 LOB
  4. 腾讯AI Lab开源大规模高质量中文词向量数据,800万中文词随你用
  5. Android 弹出对话框
  6. k8s pod MySQL环境变量,如何使用Kubernetes的configmap通过环境变量注入到pod里
  7. 如何获得一个集合的所有子集合?
  8. 数据结构之二叉树:二叉查找树基本功能,Python代码实现——10
  9. 使用Python编写自己的个人密码管理器
  10. 如何在Linux桌面环境下自动启动程序?
  11. 汇编画图题:存储器扩展(重要)
  12. [UE4]复制引起的重复对象
  13. ArrayList的add方法值被覆盖(android项目)
  14. DNS-实验3_委派子域和转发
  15. canvas+websocket+vue做一个你画我猜小游戏
  16. 认知诊断理论的前世今生
  17. linux重装声卡驱动,linux声卡驱动重装
  18. Unity中摄像机绕物体旋转和拉近拉远视角的操作
  19. 三维计算机动画的特征是真实性,3D动画电影的应用特点及制作管理内容
  20. Laravel之数据库操作与Eloquent模型使用总结

热门文章

  1. 大话数据结构(个人笔记)
  2. php模板引擎smarty案例下载,Smarty下载|Smarty(php模板引擎) v3.1.30官方版 - 121下载站...
  3. python读取大智慧数据_大智慧数据格式
  4. wpa_supplicant使用
  5. 编程常用英语单词,文末有我工作中收集的自用的
  6. 小小flash动画_信息追梦人 | 动画制作专业优秀毕业生周海倩
  7. 丰收互联蓝牙key怎么开机_蓝牙UKEY使用说明
  8. 转一段群里看到的小诗,银才啊银才!
  9. 梦幻西游五虎将访谈系列:主策划小白
  10. 移动端分享链接给微信好友