首先, 附上一张Shiro核心架构图
配置要点
配置Security Manager
创建并配置Realm
在使用JWT作为凭证的web应用中, 需要有这两个Realm:
- UsernamePasswordRealm
- JWTRealm
其中UsernamePasswordRealm用于登录, JWTRealm用于对header中携带jwt的请求
配置Authenticator
在Authenticator中, 可以配置验证器的相关行为. 验证器调用Realm的doAuthentication()返回验证信息. 可以对返回的token信息(正确的验证信息)和http中的信息(用户提交的验证信息)进行校验.
在Authenticator中, 一项重要配置就是: 为验证过程配置全局异常处理. 因为默认的Authenticator会将抛出的异常catch住, 因此在Realm的doAuthentication()方法中抛出的异常无法被全局异常处理程式访问到.
实现自己的AuthenticationStrategy, 并进行设置, 即可解决异常处理问题.
getAuthenticationInfo()中抛出异常, 全局异常处理却收不到自己抛出的异常
配置Filter
Shiro的验证过程通过拦截器filter实现.
在JWT场景中, 为了让Shiro对header中的jwt信息进行校验, 必须对默认的拦截器authc进行自定义.
Filter中的依赖注入
在配置的过程中, 一个坑点就是: 如果你希望将你的JWTUtil工具类(或许其它)通过依赖注入的方式注入到你的自定义filter中, 绝对不能使用Autowired注解, 因为filter的初始化早于beans的初始化, 因此是无法将bean通过autowired注入到filter类中的. 解决方法是: 通过为filter类增添构造函数, 在构造函数中传入ApplicationContext, 然后在通过context获取bean.
MyJWTUtil util;
public LoginFilter(ApplicationContext context) {
this.util = context.getBean(MyJWTUtil.class);
}
filterFactoryBean.getFilters().put("authc", new LoginFilter(applicationContext));
Filter的token生成
除了在controller登录时生成token外, 还可以在flter中生成token, 以供校验使用. 按道理来说, 一种Filter可以配置多种token. 但对于实际开发而言, 通常一种Filter只对应一种token. 在JWT中就是配置Filter专门用于处理JWT. 在Filter中就要生成JWTToken
Filter装配
将默认的和自带的Filter进行装配. 通常一个Filter可以配置多个url.
@Autowired
ApplicationContext applicationContext;
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(securityManager);
HashMap<String, String> filtersMap = new LinkedHashMap<>();
filterFactoryBean.getFilters().put("authc", new LoginFilter(applicationContext));
filtersMap.put("/login/common", "anon");
filtersMap.put("/**", "authc");
filterFactoryBean.setFilterChainDefinitionMap(filtersMap);
return filterFactoryBean;
}
附: Filter的代码
@Data
public class LoginFilter extends AuthenticatingFilter {
@Autowired
public ObjectMapper mapper = new ObjectMapper();
@Autowired
public MyJWTUtil util;
public LoginFilter(ApplicationContext context) {
this.util = context.getBean(MyJWTUtil.class);
}
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
if (!(request instanceof HttpServletRequest)){
return null;
}
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String jwt = httpServletRequest.getHeader("Authorization");
JWTToken token = new JWTToken();
token.setId(util.getClaimOfToken(jwt).getSubject());
token.setJwt(jwt);
return token;
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
boolean res = false;
try {
res = executeLogin(request, response);
} catch (Exception exception) {
exception.printStackTrace();
}
return res;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json; charset=utf-8");
response.getWriter().write(mapper.writeValueAsString(ResultModel.create().setMsg("Without Logging in")));
// 返回true表示继续处理流程, false直接退出
return false;
}
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
response.setContentType("application/json; charset=utf-8");
response.getWriter().write(mapper.writeValueAsString(ResultModel.create().setMsg("Without Logging in")));
}
}
本文介绍了在SpringBoot中结合Shiro和JWT进行权限管理的配置要点,包括配置Security Manager、创建Realm、定制Authenticator以及自定义Filter。在配置Security Manager时,重点讨论了UsernamePasswordRealm和JWTRealm的创建。对于Authenticator,强调了异常处理的配置。在Filter部分,阐述了如何处理依赖注入问题以及如何生成和校验JWTToken。

7564

被折叠的 条评论
为什么被折叠?



