1.集成了shiro之后,swagger2页面总是报错,报类型转换错误。swagger2 json转换错误。如果springboot采用gson做的json转换,必须自定义类转换。
@Bean
public GsonHttpMessageConverter gsonHttpMessageConverter() {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setGson(new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd HH:mm:ss")
.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter()).create());
return converter;
}
// 使用gson格式时候,会报错。
class SpringfoxJsonToGsonAdapter implements JsonSerializer<Json> {
@Override
public JsonElement serialize(Json src, Type typeOfSrc, JsonSerializationContext context) {
final JsonParser parser = new JsonParser();
return parser.parse(src.value());
}
}
2.shiro会话类无法转换,使用了devtools模式时,shiro 会话类加载不一致。导致类型转换错误。定义spring-devtools.properties配置文件。把会话类所在的jar包排除。或者把shiro的包用热加载。
3.swagger2 页面能正常访问,但是模拟接口报错。
思路一,swagger2 应该可以配置请求头的地方,吧shiro的会话信息带上,这样可以访问模拟接口。我没找到方法。
思路二,对于swagger2 请求的接口,放开请求,shiro放开拦截。测试环境开启,生产环境关闭
这是对页面请求的配置。保证测试环境能够访问页面,生产环境关闭页面。
public class TestAuthenticationFilter extends AuthenticationFilter {
// private static final Logger log = LoggerFactory.getLogger(TestAuthenticationFilter.class);
protected static boolean testEnvironment=false;
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isTestEnvironment()) {
return true;
}
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().write(JSON.toJSONString(ResultBuilder.genExpResult(new BizException(BaseExcCodesEnum.NO_RIGHT))));
return false;
}
public static boolean isTestEnvironment() {
return testEnvironment;
}
public static void setTestEnvironment(boolean testEnvironment) {
TestAuthenticationFilter.testEnvironment = testEnvironment;
}
}
@Bean
protected ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setLoginUrl("/manager/login");
shiroFilter.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();
TestAuthenticationFilter testAuthenticationFilter=new TestAuthenticationFilter();
TestAuthenticationFilter.setTestEnvironment(env.getProperty("app.testEnvironment",Boolean.class));
ApiAuthenticationFilter apiAuthenticationFilter=new ApiAuthenticationFilter();
filters.put("test",testAuthenticationFilter);
filters.put("api",apiAuthenticationFilter);
shiroFilter.setFilters(filters);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/statics/**", "anon");
filterMap.put("/js/**", "anon");
filterMap.put("/favicon.ico", "anon");
filterMap.put("/sys/manager/login", "anon");
filterMap.put("/sys/manager/forgetPassword", "anon");
filterMap.put("/sys/manager/captcha", "anon");
filterMap.put("/sys/manager/logout", "anon");
filterMap.put("/swagger-ui.html", "test");
filterMap.put("/swagger-resources/**", "test");
filterMap.put("/image/**","test");
filterMap.put("/v2/api-docs", "test");
filterMap.put("/webjars/**", "test");
filterMap.put("/**", "api");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
对权限的判断,测试环境开启无需验证shiro权限。
@Bean
public TestAopAllianceAnnotationsAuthorizingMethodInterceptor apiAopAllianceAnnotationsAuthorizingMethodInterceptor() {
TestAopAllianceAnnotationsAuthorizingMethodInterceptor aopAllianceAnnotationsAuthorizingMethodInterceptor = new TestAopAllianceAnnotationsAuthorizingMethodInterceptor();
aopAllianceAnnotationsAuthorizingMethodInterceptor.setTestEnvironment(env.getProperty("app.testEnvironment",Boolean.class));
return aopAllianceAnnotationsAuthorizingMethodInterceptor;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
advisor.setAdvice(apiAopAllianceAnnotationsAuthorizingMethodInterceptor());
return advisor;
}
public class TestAopAllianceAnnotationsAuthorizingMethodInterceptor extends AopAllianceAnnotationsAuthorizingMethodInterceptor {
private boolean testEnvironment = false;
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
if (testEnvironment) {
return mi.proceed();
} else {
return super.invoke(mi);
}
}
public boolean isTestEnvironment() {
return testEnvironment;
}
public void setTestEnvironment(boolean testEnvironment) {
this.testEnvironment = testEnvironment;
}
}
4. shiro 事务不生效问题
如果定义的Realm引用了service,延迟Realm实现中Service对象的初始化时间,这样就可以保证Service实际初始化的时候会被BeanPostProcessor拦截,
public class UserNamePassWordRealm extends AbstractUserRealm {
private static final Logger logger = LoggerFactory.getLogger(UserNamePassWordRealm.class);
@Autowired
@Lazy
//创建具有事务功能的代理对象
private UserService userService;
5.跨域问题,跨域访问会发送option请求,请求会被shiro拦截报跨域问题,
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
HttpServletResponse httpResponse = WebUtils.toHttp(response);
if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
String originHeader = httpRequest.getHeader("Origin");
if(allowOrigins.contains(originHeader)){
httpResponse.setHeader("Access-control-Allow-Origin",originHeader);
httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
httpResponse.setHeader("Access-Control-Allow-Headers","Origin,Accept,x-requested-with,content-type,X-AUTH-SESSION");
httpResponse.setHeader("Access-Control-Expose-Headers", "X-AUTH-SESSION");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
httpResponse.setStatus(HttpStatus.OK.value());
return true;
}
}
Subject subject = getSubject(request, response);
return subject.isAuthenticated();
}