shiro 前后端分离_前后端分离架构下,如何通过shiro进行认证和权限控制?

Apache Shiro是一个强大且易用的Java安全框架,用于执行身份验证、授权、密码和会话管理,无论什么时候,用户认证和权限控制都是一个永恒的话题,前后端分离是当前很火的一种开发模式,便于前、后端人员专注于自己的逻辑实现,也更有利于大规模协作开发,在此开发模式下,如何使用shiro呢?本文的方案基于token认证授权,来自于实际项目,现将主要思路整理出来分享给大家,欢迎探讨,如需要源码请私信联系。

一、开发环境

  1. 前端:任何一种前端框架(如Vue、Angular等)
  2. 后端:springboot

二、主要逻辑

  1. 用户通过账号密码(身份+凭证)登录网站(前端页面调用后端登录接口,传入身份和凭证)
  2. 后端程序登录,并生成对应token给前端网页(token和用户id绑定并入库)
  3. 前端网页后续访问均带上token
  4. 后端通过token识别用户,并获得用户的访问权限
  5. 后端根据用户访问权限决定是否放行
471a750d84a60e29d0c619b7b5aa4274.png

shiro认证、授权序列图

三、对上图解释说明

  1. shiro最核心的两个过程为认证和授权,认证为识别用户的过程,授权为判断用户是否有权访问的过程
  2. 上图中的认证Filter要继承AuthenticatingFilter,并override如下方法:

(1)createToken
(2)isAccessAllowed---本方法直接返回false,即交给onAccessDenied方法处理
(3)onAccessDenied---调用executeLogin进行登录

public class OAuth2Filter extends AuthenticatingFilter {    Logger logger = LoggerFactory.getLogger(this.getClass());    @Override       protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {        //获取请求token        String token = getRequestToken((HttpServletRequest) request);        if (StringUtils.isBlank(token)) {            return null;        }        return new OAuth2Token(token);    }    @Override        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {      //仅为“option”时返回true       if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {            return true;        }        return false;    }    @Override        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        //获取请求token,如果token不存在,直接返回401              String token = getRequestToken((HttpServletRequest) request);        if (StringUtils.isBlank(token)) {            HttpServletResponse httpResponse = (HttpServletResponse) response;            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");            httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());            String json = JSON.toJSONString(R.error(HttpStatus.SC_UNAUTHORIZED, "invalid token"));            httpResponse.getWriter().print(json);            return false;        }        return executeLogin(request, response);    }......}

3、自定义Realm需要继承AuthorizingRealm,并overide如下方法:

(1)supports---需要支持上述Filter的createToken方法中返回的类型

(2)doGetAuthenticationInfo --- 返回 SimpleAuthenticationInfo(user, token, realmName)

(3)doGetAuthorizationInfo

@Componentpublic class OAuth2Realm extends AuthorizingRealm {    @Autowired      private ShiroService shiroService;    @Override      public boolean supports(AuthenticationToken token) {        return token instanceof OAuth2Token;    }    /* *    * 授权(验证权限时调用)         */      @Override     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        SysUserEntity user = (SysUserEntity) principals.getPrimaryPrincipal();        Long userId = user.getUserId();        //用户权限列表                Set permsSet = shiroService.getUserPermissions(userId);        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        info.setStringPermissions(permsSet);        return info;    }    /**         * 认证(登录时调用)         */      @Override      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)   throws AuthenticationException {        String accessToken = (String) token.getPrincipal();        //根据accessToken查询用户信息           SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken);        //token失效            if (tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {            throw new IncorrectCredentialsException("token失效,请重新登录");        }        //查询用户信息           SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId());        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());        return info;    }}

4、上述Token管理器需要自定义Token的实现,需要继承AuthenticationToken,并override如下方法:

(1)getPrincipal---返回身份,此方案直接返回token字符串

(2)getCredentials---返回凭证,此方法直接返回token字符串

public class OAuth2Token implements AuthenticationToken {    private static final long serialVersionUID = 1L;    private String token;    public OAuth2Token(String token) {        this.token = token;    }    @Override       public String getPrincipal() {        return token;    }    @Override        public Object getCredentials() {        return token;    }}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值