前后端分离项目中 springboot 集成 shiro 实现权限控制

文章目录

      • 使用注解控制鉴权授权
      • 使用 url配置控制鉴权授权
      • 表结构
      • jar 包依赖
      • 代码说明
        • 身份认证
        • 权限认证
      • 跨域问题解决
      • 登录验证不进行重定向改为设置http状态
      • 项目源码
      • Reference

使用注解控制鉴权授权

注解 功能
@RequiresGuest 只有游客可以访问
@RequiresAuthentication 需要登录才能访问
@RequiresUser 已登录的用户或“记住我”的用户能访问
@RequiresRoles 已登录的用户需具有指定的角色才能访问
@RequiresPermissions 已登录的用户需具有指定的权限才能访问

 

使用 url配置控制鉴权授权

配置缩写 对应的过滤器 功能
anon AnonymousFilter 指定url可以匿名访问
authc FormAuthenticationFilter 指定url需要form表单登录,默认会从请求中获取usernamepassword,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。
authcBasic BasicHttpAuthenticationFilter 指定url需要basic登录
logout LogoutFilter 登出过滤器,配置指定url就可以实现退出功能,非常方便
noSessionCreation NoSessionCreationFilter 禁止创建会话
perms PermissionsAuthorizationFilter 需要指定权限才能访问
port PortFilter 需要指定端口才能访问
rest HttpMethodPermissionFilter 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释
roles RolesAuthorizationFilter 需要指定角色才能访问
ssl SslFilter 需要https请求才能访问
user UserFilter 需要已登录或“记住我”的用户才能访问

 

表结构

注释
sys_user 用户表
sys_role 角色表
sys_user_role 用户角色关联表
sys_role_permission 角色权限关联表
sys_permission 权限表

 

jar 包依赖

<dependency>
	<groupId>org.apache.shirogroupId>
	<artifactId>shiro-springartifactId>
	<version>1.3.2version>
dependency>

 

代码说明

身份认证

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    // 根据用户名获取用户密码
    User user = userService.findUserByLoginName(token.getUsername());

    if (user == null) {
        throw new AuthenticationException(String.valueOf(ResponseEnum.ERROR_INCORRECT_UNAME_OR_PWD.code()));
    }

    ByteSource salt = ByteSource.Util.bytes(user.getSalt());

    String password = user.getPassword();
    String saltPassword = ShiroUtil.saltEncrypt(token.getPassword(), user.getSalt());

    if (null == password) {
        throw new AuthenticationException(String.valueOf(ResponseEnum.INVALID_USER.code()));
    } else if (!password.equals(saltPassword)) {
        throw new AuthenticationException(String.valueOf(ResponseEnum.PASSWORD_ERROR.code()));
    }
    return new SimpleAuthenticationInfo(token.getPrincipal(), token.getPassword(), salt, getName());
}

在执行 subject.login(token) 时 会调用 doGetAuthenticationInfo 方法代码

 

权限认证

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    String username = (String) principalCollection.getPrimaryPrincipal();
    SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

    // 根据 用户名称 获取用户的 角色信息
    Set<String> roles = userService.findUserRolesByLoginName(username);
    // 设置该用户拥有的角色 @RequiresRoles
    if (roles.size() > 0) {
        simpleAuthorizationInfo.setRoles(roles);
    }

    // 设置用户的权限列表 @RequiresPermissions
    Set<String> userPermissions = userService.findUserPermissionsByLoginName(username);
    if (userPermissions.size() > 0) {
        simpleAuthorizationInfo.setStringPermissions(userPermissions);
    }

    return simpleAuthorizationInfo;
}

在接口标明注解 @RequiresPermissions@RequiresRoles 时会调用 doGetAuthorizationInfo 方法

// `/admin/**` 下的接口需要管理员权限, 等同于在对应接口上加 @RequiresRoles(value = {"admin", "user"}, logical = Logical.OR)
filterChainDefinitionMap.put("/admin/**", "roles[admin,user]");
// `/user/**` 下的接口需要的权限, 等同于在对应接口上加 @RequiresPermissions("order:query")
filterChainDefinitionMap.put("/user/**", "perms[user:query]");

或者 ShiroConfigShiroFilterFactoryBean 对象中配置了以上权限代码时也会调用 doGetAuthorizationInfo 方法

 

跨域问题解决

@Configuration
public class CorsConfig {

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);

        // 指定运行地址
        corsConfiguration.setAllowedOrigins(Lists.newArrayList("http://192.168.10.1:8080"));
        // 允许任何域名
//        corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);

        // 允许任何头部信息
        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
        // 允许所有请求类型
        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
        corsConfiguration.addExposedHeader("Authorization");
        source.registerCorsConfiguration("/**", corsConfiguration);
        FilterRegistrationBean bean = new FilterRegistrationBean<>(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }

}

 

登录验证不进行重定向改为设置http状态

public class AiAuthenticationFilter extends FormAuthenticationFilter {
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws Exception {
        WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }
}

// 修改 ShiroConfig 的 shiroFilter 方法
@Configuration
public class ShiroConfig {
	@Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();
        filterMap.put("authc", new AiAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filterMap);

        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/unauth");
        // 设置重定向接口地址
//        shiroFilterFactoryBean.setLoginUrl("/api/user/v1/notLogin");
        shiroFilterFactoryBean.setUnauthorizedUrl("/api/user/v1/notPerms");

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/api/external/**", "anon");
        filterChainDefinitionMap.put("/api/user/v1/login", "anon");
        filterChainDefinitionMap.put("/api/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }
}

 

项目源码

项目源码 Github 地址: springboot-shiro

 

Reference

  • Shiro用starter方式优雅整合到SpringBoot中
  • 教你 Shiro 整合 SpringBoot,避开各种坑

你可能感兴趣的:(Spring,框架类,开发笔记)