springboot整合shiro与自定义过滤器
yx726843014 人气:0filter自定义过滤器 增加了 对验证码的校验
package com.youxiong.filter; import com.youxiong.shiro.UsernamePasswordKaptchaToken; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; public class FormValid extends FormAuthenticationFilter { private String kaptcha = "KAPTCHA_SESSION_KEY"; public FormValid() { super(); } //用户未登录 /* @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpSession session = httpServletRequest.getSession(); String kaptchaCode = (String) session.getAttribute(kaptcha); String code = httpServletRequest.getParameter("code"); if(code!=null&&kaptchaCode!=null&&!kaptchaCode.equals(code)){ httpServletRequest.setAttribute("shiroLoginFailure","codeError"); return true; } return super.onAccessDenied(request, response); } */ //用户提交表单时候 创建的token @Override protected AuthenticationToken createToken( ServletRequest request, ServletResponse response) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String code = (String) httpServletRequest.getParameter("kaptcha"); String host = getHost(request); String username = getUsername(request); String password = getPassword(request); boolean rememberMe = isRememberMe(request); System.out.println("create token--------------code------>one "+code); return new UsernamePasswordKaptchaToken(username,password.toCharArray(),rememberMe,host,code); } }
自定义UsernamePassword是为了接收前台发送过来的数据
package com.youxiong.shiro; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import java.io.Serializable; public class UsernamePasswordKaptchaToken extends UsernamePasswordToken { private static final long serialVersionUID = 1L; private String kaptcha; public UsernamePasswordKaptchaToken(){ super(); } public UsernamePasswordKaptchaToken(String username, char[] password, boolean rememberMe, String host, String kaptcha) { super(username, password, rememberMe, host); this.kaptcha = kaptcha; } public String getKaptcha() { return kaptcha; } public void setKaptcha(String kaptcha) { this.kaptcha = kaptcha; } }
shiro配置
package com.youxiong.config; import com.google.code.kaptcha.servlet.KaptchaServlet; import com.youxiong.dao.UserReposisty; import com.youxiong.domain.Permission; import com.youxiong.domain.Role; import com.youxiong.domain.UserInfo; import com.youxiong.filter.FormValid; import com.youxiong.redis.JedisCacheManager; import com.youxiong.redis.RedisSessionDao; import com.youxiong.redis.RedisSessionListener; import com.youxiong.redis.RediseSessionFactory; import com.youxiong.shiro.MyShiroRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.SessionListener; import org.apache.shiro.session.mgt.SessionFactory; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; import org.apache.shiro.session.mgt.eis.SessionDAO; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; import javax.servlet.Filter; import java.util.*; @Configuration public class ShiroConfig { @Autowired private UserReposisty userReposisty; @Bean public ShiroFilterFactoryBean createShiroFilter(SecurityManager securityManager) { System.out.println("--------ShiroFilterFactoryBean-------"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, Filter> filterMap = new HashMap<>(); //map里面key值要为authc才能使用自定义的过滤器 filterMap.put("authc", formValid()); // can go to login shiroFilterFactoryBean.setLoginUrl("/login.html"); //doLogin success go to page shiroFilterFactoryBean.setSuccessUrl("/success.html"); //do not Unauthorized page shiroFilterFactoryBean.setUnauthorizedUrl("/403.html"); Map<String, String> map = new LinkedHashMap<String, String>(); //验证码的路径 不要跟下面需要认证的写在一个路径里 会被拦截的 map.put("/servlet/**", "anon"); //需要把要授权的URL 全部装到filterChain中去过滤 UserInfo userInfo = userReposisty.findByUid(1); for (Role role : userInfo.getRoles()) { for (Permission permission : role.getPermissions()) { if (permission.getUrl() != "") { String permissions = "perms[" + permission.getPermission() + "]"; map.put(permission.getUrl(), permissions); } } } map.put("/user*/*", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); shiroFilterFactoryBean.setFilters(filterMap); return shiroFilterFactoryBean; } //自己定义realm @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); //缓存管理 securityManager.setCacheManager(jedisCacheManager()); //会话管理 securityManager.setSessionManager(sessionManager()); return securityManager; } //密码盐 可以不必实现 因为一般密码可以自己定义自己的密码加密规则 /* @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5"); hashedCredentialsMatcher.setHashIterations(2); return hashedCredentialsMatcher; }*/ //开启aop注解 @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean(name = "simpleMappingExceptionResolver") public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() { SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver(); Properties mappings = new Properties(); mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理 mappings.setProperty("UnauthorizedException", "403"); r.setExceptionMappings(mappings); // None by default r.setDefaultErrorView("error"); // No default r.setExceptionAttribute("ex"); // Default is "exception" //r.setWarnLogCategory("example.MvcLogger"); // No default return r; } //servlet注册器 -----》验证码的路径 @Bean public ServletRegistrationBean servletRegistrationBean() { System.out.println("----验证码---"); return new ServletRegistrationBean(new KaptchaServlet(), "/servlet/kaptcha.jpg"); } //自定义过滤器 ---》里面实现了对验证码校验 @Bean("myFilter") public FormValid formValid() { return new FormValid(); } //jedis缓存 @Bean public JedisCacheManager jedisCacheManager() { return new JedisCacheManager(); } @Bean public SessionManager sessionManager() { DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager(); defaultWebSessionManager.setSessionIdCookie(simpleCookie()); defaultWebSessionManager.setSessionDAO(sessionDAO()); //可以设置shiro提供的会话管理机制 //defaultWebSessionManager.setSessionDAO(new EnterpriseCacheSessionDAO()); return defaultWebSessionManager; } //这里就是会话管理的操作类 @Bean public SessionDAO sessionDAO() { return new RedisSessionDao(); } //这里需要设置一个cookie的名称 原因就是会跟原来的session的id值重复的 @Bean public SimpleCookie simpleCookie() { SimpleCookie simpleCookie = new SimpleCookie("REDISSESSION"); return simpleCookie; } }
Shiro中的权限控制
#需要同时拥有order:add和order:query权限才可以访问 /order-add = perms["order:add","order:query"] #只需要order:del权限就可以访问 /order-del = perms["order:del"]
perms表示的就是权限控制,中括号中就是需要访问等号之前路径,需要的权限名称。如果在使用Shiro过滤器的时候,不配置过滤器,就会使用默认的过滤器。
以下是默认权限过滤器的源码。
public class PermissionsAuthorizationFilter extends AuthorizationFilter { public PermissionsAuthorizationFilter() { } public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { Subject subject = this.getSubject(request, response); String[] perms = (String[])mappedValue; boolean isPermitted = true; if (perms != null && perms.length > 0) { if (perms.length == 1) { if (!subject.isPermitted(perms[0])) { isPermitted = false; } } else if (!subject.isPermittedAll(perms)) { isPermitted = false; } } return isPermitted; } }
从上面的代码可以看出,我们的配置会默认被强转为string类型的字符串数组。当只有一个权限时,会直接判断有没有该权限; 当配置多个权限时,从下面的代码可以看出只用在请求url的用户拥有所有的权限时,才会返回true,否则就会被拒绝访问。
总结
加载全部内容