这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
前言
要说现在 Java
端的哪个开发框架最流行,那肯定非 SpringBoot
莫属了,SpringBoot
最大的好处是可以省去很多的配置,开箱即用。但要说到权限控制类框架,那就各有千秋了,每个框架都有各自的特点,咱今天要介绍的是一款经典老牌类的权限框架--Apache Shiro
。
构建项目
使用阿里云的镜像地址创建项目,start.aliyun.com/bootstrap.h…
添加 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容器中
此部分主要配置sessionManager
和securityManager
,一般情况下保持默认即可,在配置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…
测试:
- 测试不拦截登录:http://localhost:8080/emp/login
- 测试拦截登录:http://localhost:8080/emp/admin
- 测试权限不正确:http://localhost:8080/emp/admin?token=adminToken
- 测试权限不正确:http://localhost:8080/emp/admin?token=normalToken
结语
分享一个有助于自律的思考方式,当我们要做某件事时,我们一定要去想做这件事的坏处,这样就可以抑制我们大脑对这件事多巴胺的分泌,而大部分长效收益的事情坏处都不多,而短效收益的事情坏处就很多,这样坚持下去,我们的大脑在再次遇到短效收益的事情时就不会那么的兴奋了。
近期评论