A. 怎么自定义shiro中的过滤器来允许ajax请求后台数据
自定义过滤器:
public class extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
return executeLogin(request, response);
} else {
// 放行 allow them to see the login page ;)
return true;
}
} else {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
if (ShiroFilterUtils.isAjax(httpRequest)) {
HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
httpServletResponse.sendError(ShiroFilterUtils.HTTP_STATUS_SESSION_EXPIRE);
return false;
} else {
saveRequestAndRedirectToLogin(request, response);
}
return false;
}
}
/**
* 判断ajax请求
* @param request
* @return
*/
boolean isAjax(HttpServletRequest request){
return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString()) ) ;
}
}
封装ajax
var Error = function () {
return {
// 初始化各个函数及对象
init: function () {
},
// 显示或者记录错误
displayError: function(response, ajaxOptions, thrownError) {
if (response.status == 404) {// 页面没有找到
pageContent.load($("#hdnContextPath").val() + "/page/404.action");
} else if (response.status == 401) {// session过期
SweetAlert.errorSessionExpire();
} else if (response.status == 507) {// 用户访问次数太频繁
SweetAlert.error("您的访问次数太频繁, 请过一会再试...");
} else {//其他错误
window.location = $("#hdnContextPath").val() + "/page/500.action";
}
console.log(thrownError);
}
};
}();
jQuery(document).ready(function() {
Error.init();
});
JS的引用处如下:
App.blockUI();
$.ajax({
url: $("#hdnContextPath").val() + "/feedback/queryFeedBackDetail.action",
type: "POST",
async: false,
data: {"feedbackId": feedbackId, "userId": userId, "status": status},
success: function(data) {
// 忽略
B. shiro 拦截器formauthenticationfilter这个过滤器什么情况有作用
springmvc的拦截器是优先级高于shiro的,shiro就是自定义实现了spring mvc的filter吧,如果足够牛逼的话是可以不用shiro的,完全可以自己实现安全拦截的
C. 如何正确的使用shiro
从来没接触过shiro Java安全框架,突然有一天需要要用用户登陆验证和用户角色权限的任务,而且是针对shiro 进行整合,开始收到任务,心都有点凉凉的。经过一轮的搜索,感觉没多大的收获。很多用户的角色都是写在xml配置文件中。觉得太不人性化了,想换个用户角色还得改xml?我觉得这么强大的框架应该不可能这么狗血的存在。然后认真的看文档,发现真的是可以直接读取数据库的。我把我搭建的流程发布在此。有问题的可以交流交流。我写的也并不是正确的,只能参考参考。
1.web.xml的配置
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.shiro.ini配置
[main]
[filters]
#自定义realm
shiroAuthorizingRealm = com.frame.security.ShiroAuthorizingRealm
securityManager.realm = $shiroAuthorizingRealm
# 声明一个自定义的用户校验拦截器
= com.frame.security.
# 声明一个自定义的用户角色权限拦截器
= com.frame.security.
#cache
shiroCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
shiroCacheManager.cacheManagerConfigFile = classpath:ehcache.xml
securityManager.cacheManager = $shiroCacheManager
#session
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.globalSessionTimeout = 1800000
securityManager = org.apache.shiro.web.mgt.DefaultWebSecurityManager
[urls]
/admin/user/login = anon
/admin/user/logout = anon
/admin/user/registered = anon
/admin/** = ,
从shiro.ini配置中可以看出,需要三个文件,分别为ShiroAuthorizingRealm.java(realm文件),.java(自定义用户登陆验证文件),(自定义用户角色权限文件);
在urls配置中可以看出不需要拦截的url后面加上anon便可,但有先后顺序。
缓存是使用ehcache
3.ehcache.xml配置
<cache name="defaultCache" maxElementsInMemory="500"
maxElementsOnDisk="10000000" eternal="true" overflowToDisk="true"
diskSpoolBufferSizeMB="50" />
<cache name="shiro-activeSessionCache" maxElementsInMemory="500"
maxElementsOnDisk="10000000" eternal="true" overflowToDisk="true"
diskSpoolBufferSizeMB="50" />
<cache name="jdbcRealm.authorizationCache" maxElementsInMemory="500"
maxElementsOnDisk="10000000" eternal="true" overflowToDisk="true"
diskSpoolBufferSizeMB="50" />
<cache name="authorization" maxElementsInMemory="500"
timeToLiveSeconds="3600" eternal="false" overflowToDisk="false" />
4.ShiroAuthorizingRealm.java
public class ShiroAuthorizingRealm extends AuthorizingRealm {
private AuthorityService authorityService = FrameContext.getBean(AuthorityService.class);
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("=======doGetAuthenticationInfo=======");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
String username = userToken.getUsername();
String password = String.valueOf(userToken.getPassword());
User user = User..findFirst("select * from m_user where account = ?", username);
if (user != null) {//下面可以做一些登陆的操作,密码错误,用户状态等等
if(MD5Encoder.validPassword(password, user.getPassword())==false){
throw new UnknownAccountException();
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
} else {
return null;
}
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("=======doGetAuthorizationInfo=======");
User user = (User) principals.getPrimaryPrincipal();
if(user!=null){//从数据库中读取用户的角色权限,
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List<String> perms = authorityService.getUrlByUser(user);
if(perms!=null&&perms.size()>0){//调用addStringPermissions方法把用户的权限信息添加到info中,可以addRoles方法把用户的角色添加到了info中
info.addStringPermissions(perms);
}
return info;
}
return null;
}
}
5..java
public class extends FormAuthenticationFilter {
private final static Logger log = Logger.getLogger(.class);
private static final String contentType = "application/json; charset=UTF-8";
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
HttpServletResponse httpResponse = WebUtils.toHttp(response);
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
return true;
}
} else {
Result<Object> result = new Result<Object>(false, "401", "没有授权,请先登录", null);
renderJson(httpResponse, result);
return false;
}
}
private void renderJson(HttpServletResponse response, Object object) {
String jsonText = JsonKit.toJson(object);
PrintWriter writer = null;
try {
response.setHeader("Pragma", "no-cache"); // HTTP/1.0 caches might not implement Cache-Control and might only implement Pragma: no-cache
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(contentType);
writer = response.getWriter();
writer.write(jsonText);
writer.flush();
} catch (IOException e) {
throw new RenderException(e);
}
finally {
if (writer != null) {
writer.close();
}
}
}
}
6..java
public class extends {
private static final String contentType = "application/json; charset=UTF-8";
private AuthorityService authorityService = McmsContext.getBean(AuthorityService.class);
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
if(getMappedValue(request)!=null){
return super.isAccessAllowed(request, response, getMappedValue(request));
}
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
// TODO Auto-generated method stub
HttpServletRequest httpRequest = WebUtils.toHttp(request);
HttpServletResponse httpResponse = WebUtils.toHttp(response);
String path = httpRequest.getServletPath();
Subject subject = getSubject(request, response);
if (subject.isPermitted(path)) {
return true;
} else {
Result<Object> result = new Result<Object>(false, "401", "抱歉,您没有该权限!", null);
renderJson(httpResponse, result);
return false;
}
}
/**
* 得到mappedValue,相当于perms[user:add]中的“user:add”
* @param path
* @return
*/
public String[] getMappedValue(ServletRequest request) {
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getServletPath();
String code = getCodesByPath(path);
if(null == code) {
return null;
}
return new String[]{code};
}
/**
* 根据访问路径获取权限代码
* @param path
* @return
*/
public String getCodesByPath(String path) {
User user = (User) SecurityUtils.getSubject().getPrincipal();
String pers = authorityService.getUrlByUserPath(path,user);
return Optional.ofNullable(pers).orElse(null);
}
private void renderJson(HttpServletResponse response, Object object) {
String jsonText = JsonKit.toJson(object);
PrintWriter writer = null;
try {
response.setHeader("Pragma", "no-cache"); // HTTP/1.0 caches might not implement Cache-Control and might only implement Pragma: no-cache
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(contentType);
writer = response.getWriter();
writer.write(jsonText);
writer.flush();
} catch (IOException e) {
throw new RenderException(e);
}
finally {
if (writer != null) {
writer.close();
}
}
}
}
7.用户登陆入口
public void login() {
String account = getPara("account");
String password = getPara("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken tokens = new UsernamePasswordToken(account, password);
tokens.setRememberMe(false);
try {
subject.login(tokens);
User user = (User) subject.getPrincipal();
loginSuccess(user);
UserVo userVo = convertToUserVO(user);
renderSucessResult(userVo);
} catch (UnknownAccountException ue) {
tokens.clear();
renderFailedResult("登录失败!无效的账号或密码!");
} catch (IncorrectCredentialsException ie) {
tokens.clear();
renderFailedResult("用户已注销!");
} catch(LockedAccountException le){
tokens.clear();
renderFailedResult("账号被锁定!");
} catch (RuntimeException re) {
re.printStackTrace();
tokens.clear();
renderFailedResult("登录失败!");
}
}
数据库可以自己去设计,这里就不提供了。
参照上面的去整合框架,便可以使用了,这样搭建适合多种框架的整合。
D. springMvc+shiro做权限管理时为什么页面上没有显示内容
正常情况是不会出现这样的,shiro对于静态资源的处理,不用特殊配置。
只需要在shiroFilter过滤器filterChainDefinitions项中增加一个静态资源处理规则就可以,例如允许/css/开头的资源匿名访问,只需要这样一句配置就足矣。
/css/** = anon
配置完成后,未登录就可以在浏览器中直接访问css下的资源,新项目用的shiro,简单而又实用的权限框架。
E. shiro过滤器/* = authc把自己写的都拦截了,走了上面的拦截器后还是会被/*拦截
我也碰到这种情来况了,,自,发现filters.put("authc", filter_Authc());这种方式注入filter的时候,拦截顺序会失效,,,要改成new xx()这种方式才可以filters.put("authc", new Filter_Authc());
F. shiro 为什么 我一加filterchaindefinitionmap 就不工作了
规则的问题,规则有问题,那肯定就不拦截请求处理了。
推荐一套完整的Shiro Demo,免费的。
Shiro介绍文档:http://www.sojson.com/shiro
Demo已经部署到线上,地址是http://shiro.itboy.net
管理员帐号:admin,密码:sojson.com 如果密码错误,请用sojson。PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快。
G. shiro基于form表单的身份验证过滤器可否配置两个成功页面
Shiro的过滤器的配置是结合使用Spring的DelegatingFilterProxy与FactoryBean2种技术来完成自身过滤器的植入的,所版以理解Shiro的过滤器首先权要理解这2者的使用。
DelegatingFilterProxy :
Spring提供的一个简便的过滤器的处理方案,它将具体的操作交给内部的Filter对象delegate去处理,而这个delegate对象通过Spring IOC容器获取,这里采用的是Spring的FactoryBean的方式获取这个对象。
H. springMvc+shiro做权限管理,页面上的静态资源,样式图片等没有出现,用几种方式过滤试过,还是不行
正常情况是不会出现这样的,shiro对于静态资源的处理,不用特殊配置。
只需要在shiroFilter过滤器filterChainDefinitions项中增加一个静态资源处理规则就可以,例如允许/css/开头的资源匿名访问,只需要这样一句配置就足矣。
/css/** = anon
配置完成后,未登录就可以在浏览器中直接访问css下的资源,新项目用的shiro,简单而又实用的权限框架。
I. Shiro的 rememberMe 功能使用指导为什么rememberMe设置了没作用
采用这个解决方案的前提是,你必须自己先实现一个realm,不过这个我相信大家都会实现的,毕竟默认的不是jdbcRealm ,真正的项目都是要查数据库才能确定用户是否登录的。那么我就假定大家的项目中都有那么一个负责验证登录的 JdbcRealm, 并且是采用用户名密码认证的,在 doGetAuthenticationInfo 方法里面是采用如下的方法来做认证
...
info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
这个前提条件保证你的principal是username,相信大部分人根据教程做shiro的时候都采用了这种方式
STEP1 复写 FormAuthenticationFilter 的 isAccessAllowed 方法
做一个新类继承FormAuthenticationFilter ,并复写 isAccessAllowed 方法
package com.yqr.jxc.shiro;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import com.yqr.jxc.service.global.GlobalUserService;
public class RememberAuthenticationFilter extends FormAuthenticationFilter {
@Resource(name="globalUserService")
private GlobalUserService globalUserService;
/**
* 这个方法决定了是否能让用户登录
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
Subject subject = getSubject(request, response);
//如果 isAuthenticated 为 false 证明不是登录过的,同时 isRememberd 为true 证明是没登陆直接通过记住我功能进来的
if(!subject.isAuthenticated() && subject.isRemembered()){
//获取session看看是不是空的
Session session = subject.getSession(true);
//随便拿session的一个属性来看session当前是否是空的,我用userId,你们的项目可以自行发挥
if(session.getAttribute("userId") == null){
//如果是空的才初始化,否则每次都要初始化,项目得慢死
//这边根据前面的前提假设,拿到的是username
String username = subject.getPrincipal().toString();
//在这个方法里面做初始化用户上下文的事情,比如通过查询数据库来设置session值,你们自己发挥
globalUserService.initUserContext(username, subject);
}
}
//这个方法本来只返回 subject.isAuthenticated() 现在我们加上 subject.isRemembered() 让它同时也兼容remember这种情况
return subject.isAuthenticated() || subject.isRemembered();
}
}
STEP2 设置使用这个新的 AuthenticationFilter (认证过滤器)
如果你用的是spring那么
<!-- 整合了rememberMe功能的filter -->
<bean id="rememberAuthFilter" class="com.yqr.jxc.shiro.RememberAuthenticationFilter" ></bean>
<!--将之前的 /** = authc 替换成 rememberAuthFilter
...
/** = rememberAuthFilter
...
如果你用的是 ini 文件,那么
rememberAuthFilter=com.yqr.jxc.shiro.RememberAuthenticationFilter
#将之前的 /** = authc 替换成 rememberAuthFilter
...
/** = rememberAuthFilter
然后重启项目我们来测试一下,先登录一次系统,然后直接关掉浏览器,然后打开浏览器直接输入系统某个页面的地址,发现可以直接进去了,session什么的也设置好了
J. struts2过滤器<url-pattern>/mall/buy_*</url-pattern>为什么不生效
第三个写错了,web.xml中的过滤器不能写成/buy_*的方式,你如果要想使用这种方式的话,就用struts2的action的通配方式,就可以采用这样的方式来批量处理
eg: <action name="a_*" class="" method="{1}">
<result>/{1}.jsp</result>
</action>
好像是这么的,建议去看看struts2的通配action