SpringBoot+Shiro前后端分离权限控制(简单版)

1,233 阅读3分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

前言

要说现在 Java 端的哪个开发框架最流行,那肯定非 SpringBoot 莫属了,SpringBoot最大的好处是可以省去很多的配置,开箱即用。但要说到权限控制类框架,那就各有千秋了,每个框架都有各自的特点,咱今天要介绍的是一款经典老牌类的权限框架--Apache Shiro

构建项目

使用阿里云的镜像地址创建项目,start.aliyun.com/bootstrap.h…

image.png

添加 Shiro 依赖

compile 'org.apache.shiro:shiro-core:1.3.2'
compile 'org.apache.shiro:shiro-spring:1.3.2'

创建 AuthenticationToken

AuthenticationToken主要用于收集用户提交的身份(如用户名)及凭据(如密码),是身份认证是不可或缺的一部分。

/**
* Shiro令牌
*/

public class ShiroToken implements AuthenticationToken {
    private String token;
    public ShiroToken(String token) {
        this.token = token;
    }

    @Override
    public Object getPrincipal() {
        return this.token;
    }

    @Override
    public Object getCredentials() {
        return this.token;
    }
}

创建Realm

数据域,Shiro 和安全数据的连接器,通过realm获取认证授权相关信息。

/**
* Shiro认证对象
*/

@Component
public class ShiroRealm extends AuthorizingRealm {
    @Resource private EmpUsrService empUsrService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof ShiroToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        EmpUsr sysUsr = (EmpUsr) principals.getPrimaryPrincipal();
        Set<String> perms = empUsrService.findPermissionsByUsrId(sysUsr.getId());
        SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
        authInfo.setStringPermissions(perms);
        return authInfo;
    }

    /**

    * 认证(登录时调用)

    */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String authToken = (String) token.getPrincipal();
        Optional<EmpUsr> empUsrOptional = empUsrService.findByToken(authToken);
        if (!empUsrOptional.isPresent()) {
            throw new IncorrectCredentialsException("token失效,请重新登录");
        }
        return new SimpleAuthenticationInfo(sysUsr, authToken, getName());
    }
}

配置ShiroFilter

token可以从两个地方获取,一个是header中,一个是params中,代码如下:

/**

* 获取请求的token

*/

private String getRequestToken(HttpServletRequest httpRequest){
    //从header中获取token
    String token = httpRequest.getHeader("token");
    //如果header中不存在token,则从参数中获取token
    if(StrUtil.isBlank(token)){
        token = httpRequest.getParameter("token");
    }
    return token;
}

其中还有一个地方需要注意,浏览器在发送post请求前,会先发送一个option请求去试探服务器是否连通,所以我们需要在filter中放行option的请求:

/**

* 主要解决浏览器发送POST请求前会先发送Options请求

*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
    return ((HttpServletRequest)request).getMethod().equals(RequestMethod.OPTIONS.name());
}

配置Shiro注入到Spring容器中

此部分主要配置sessionManagersecurityManager,一般情况下保持默认即可,在配置filter时,我们需要了解几种常用的类型,oauth2需要进行权限校验,anon不进行权限校验,setUnauthorizedUrl方法配置没有相关权限时跳转的url

@Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
    shiroFilter.setSecurityManager(securityManager);
    //oauth过滤
    Map<String, Filter> filters = new HashMap<>(1);
    filters.put("oauth2", new ShiroFilter());
    shiroFilter.setFilters(filters);
    Map<String, String> filterMap = new LinkedHashMap<>();
    filterMap.put("/emp/login", "anon");
    filterMap.put("/emp/**", "oauth2");
    shiroFilter.setFilterChainDefinitionMap(filterMap);
    shiroFilter.setUnauthorizedUrl("/emp/403");
    return shiroFilter;
}

现在web服务一般会在应用前方部署一层反向代理,方便以后做负载均衡和高可用,所以我们需要进行下配置,以便解决二次代理的问题。

/**

* 解决二次代理问题

*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
    proxyCreator.setProxyTargetClass(true);
    return proxyCreator;
}

@RequiresPermissions注解说明

@RequiresPermissions可接受单个值或一个数组,其中接受数组时默认的权限方式时and的方式,及多个权限都必须有,如果我们要配置只需拥有某一个权限,可以将组合方式改为or的方式。

代码和测试

仓库地址:gitee.com/lanrain/art… 测试:

  1. 测试不拦截登录:http://localhost:8080/emp/login
  2. 测试拦截登录:http://localhost:8080/emp/admin
  3. 测试权限不正确:http://localhost:8080/emp/admin?token=adminToken
  4. 测试权限不正确:http://localhost:8080/emp/admin?token=normalToken

结语

分享一个有助于自律的思考方式,当我们要做某件事时,我们一定要去想做这件事的坏处,这样就可以抑制我们大脑对这件事多巴胺的分泌,而大部分长效收益的事情坏处都不多,而短效收益的事情坏处就很多,这样坚持下去,我们的大脑在再次遇到短效收益的事情时就不会那么的兴奋了。