0
点赞
收藏
分享

微信扫一扫

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

菜菜捞捞 2022-12-03 阅读 73


文章目录

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

使用注解控制鉴权授权

注解

功能

@RequiresGuest

只有游客可以访问

@RequiresAuthentication

需要登录才能访问

@RequiresUser

已登录的用户或“记住我”的用户能访问

@RequiresRoles

已登录的用户需具有指定的角色才能访问

@RequiresPermissions

已登录的用户需具有指定的权限才能访问

 

使用 url配置控制鉴权授权

配置缩写

对应的过滤器

功能

anon

AnonymousFilter

指定url可以匿名访问

authc

FormAuthenticationFilter

指定url需要form表单登录,默认会从请求中获取​​username​​​、​​password​​​,​​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.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</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]");

或者 ​​ShiroConfig​​​ 中 ​​ShiroFilterFactoryBean​​​ 对象中配置了以上权限代码时也会调用 ​​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,避开各种坑​​


举报

相关推荐

0 条评论