<span style="background-color: rgb(192, 192, 192);"><span style="color:#33FFFF;">//springShiro.xml</span></span> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd" default-lazy-init="true"> <!-- 1-1缓存管理器用户授权信息Cache --> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <!-- 1-2会话管理器 --> <!--<bean id="sessionManager" class="com.ssm.gold.common.shirosession.DemoSessionManager"> <!– 相隔多久检查一次session的有效性,单位毫秒 –> <property name="sessionValidationInterval" value="10000"/> <!– session的失效时长,单位毫秒 –> <property name="globalSessionTimeout" value="1800000" /> <!– 删除失效的session –> <property name="deleteInvalidSessions" value="true" /> <property name="sessionValidationSchedulerEnabled" value="false" /> <property name="sessionDAO" ref="sessionDao" /> </bean>--> <!-- 1-2-1会话ID生成器 --> <!--<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" /> <bean id="demoCache" class="com.ssm.gold.common.shirosession.DemoCache" /> <bean id="sessionDao" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="sessionIdGenerator" ref="sessionIdGenerator" /> <property name="activeSessionsCache" ref="demoCache"/> </bean>--> <!-- 1-3记住我管理器 --> <!--<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!– rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)–> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" /> <property name="cookie" ref="rememberMeCookie" /> </bean>--> <!-- 1-3-1记住我cookie --> <!--<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe" /> <!– 记住我cookie生效时间30天 –> <property name="maxAge" value="2592000" /> </bean>--> <!-- 2項目自定义的Realm --> <bean id="shiroDbRealm" class="com.ssm.gold.common.realm.ShiroDbRealm"> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- 3安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroDbRealm" /> <property name="cacheManager" ref="cacheManager" /> <!--<property name="sessionManager" ref="sessionManager"/>--> <!-- <property name="rememberMeManager" ref="rememberMeManager"/>--> </bean> <!--4-1 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 --> <!-- <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <!– 表单中账号的input名称 –> <!–<property name="usernameParam" value="usercode" />–> <!– 表单中密码的input名称 –> <!–<property name="passwordParam" value="password" />–> <!– <property name="rememberMeParam" value="rememberMe"/> –> <!– loginurl:用户登陆地址,此地址是可以http访问的url地址 –> <!– <property name="loginUrl" value="/loginuser" />–> </bean>--> <!-- 4Web安全过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- Shiro安全管理器 --> <property name="securityManager" ref="securityManager" /> <!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 --> <property name="loginUrl" value="/login" /> <!-- 登录成功后要跳转的连接--> <property name="successUrl" value="/homepage" /> <span style="background-color: rgb(255, 0, 0);"><span style="color:#33FFFF;">//这里的url在自定义的realm中写死了,自己按需求修改</span></span> <!-- 用户访问未对其授权的资源时,所显示的连接 --> <property name="unauthorizedUrl" value="/unauthorizedUrl" /> <property name="filters"> <map> <!-- <entry key="authc" value-ref="formAuthenticationFilter" />--> </map> </property> <property name="filterChainDefinitions"> <value> /logout = logout <!--登出--> /loginuser = anon <!--登录方法--> /assets/** = anon <!--静态文件--> /admin/** =authc,perms[admin:manage] /** = authc </value> </property> </bean> <!-- 5保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!--6AOP式方法级权限检查开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证--> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <!--7开启shiro注解支持--> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> </beans>
//web.xml配置过滤器
<!-- spring 应用上下文监听器 主要初始化注入 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/config/applicationContext.xml /WEB-INF/config/springShiro.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Shiro 安全过滤器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>//自定义shiro权限管理器
package com.ssm.gold.common.realm; import com.ssm.gold.common.modle.Userlogin; import com.ssm.gold.common.service.UserloginService; import com.ssm.gold.common.utils.CipherUtil; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cache.Cache; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.util.HashSet; import java.util.Set; public class ShiroDbRealm extends AuthorizingRealm { private static Logger logger = LoggerFactory.getLogger(ShiroDbRealm.class); private static final String ALGORITHM = "MD5";//MD5加密 @Autowired private UserloginService userloginservice; public ShiroDbRealm() { super(); } /** * 验证登录 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; Userlogin user = userloginservice.queryUsersName(token.getUsername()); System.out.println("---------验证登录------------"); if (user != null) { System.out.println("---------登录通过------------"); CipherUtil cipher = new CipherUtil();//MD5加密 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), cipher.generatePassword(user.getPassword()), getName()); this.setSession("currentUser", user.getUsername()); return info; } else { //没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常 return null; //throw new AuthenticationException(); } } /** * 为当前登录的Subject授予角色和权限 * 经测试:本例中该方法的调用时机为需授权资源被访问时 * 经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例中默认并未启用AuthorizationCache * 个人感觉若使用了Spring3.1开始提供的ConcurrentMapCache支持,则可灵活决定是否启用AuthorizationCache * 比如说这里从数据库获取权限信息时,先去访问Spring3.1提供的缓存,而不使用Shior提供的AuthorizationCache */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { /*这里应该根据userName使用role和permission 的serive层来做判断,并将对应 的权限加进来,下面简化了这一步*/ Set<String> roleNames = new HashSet<String>(); Set<String> permissions = new HashSet<String>(); //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next() String primaryPrincipal = (String) principals.getPrimaryPrincipal(); //从数据库中获取当前登录用户的详细信息 Userlogin user = userloginservice.queryUsersName(primaryPrincipal); System.out.println("--------------权限验证-----------------------"+user.toString()); if(user != null){ System.out.println("---------权限验证通过------------"); roleNames.add(user.getUsername());//登录用户 <span style="background-color: rgb(255, 0, 0);">permissions.add("/homepage");//用户获得权限的页面URL</span> //实体类User中包含有用户角色的实体类信息 // if(null!=user.getRoles() && user.getRoles().size()>0){ // //获取当前登录用户的角色 // for(Role role : user.getRoles()){ // roleList.add(role.getName()); // //实体类Role中包含有角色权限的实体类信息 // if(null!=role.getPermissions() && role.getPermissions().size()>0){ // //获取权限 // for(Permission pmss : role.getPermissions()){ // if(!StringUtils.isEmpty(pmss.getPermission())){ // permissionList.add(pmss.getPermission()); // } // } // } // } // } }else{ //throw new AuthorizationException(); //若该方法什么都不做直接返回null的话,就会导致任何用户访问/admin/listUser.jsp时都会自动跳转到unauthorizedUrl指定的地址 //详见applicationContext.xml中的<bean id="shiroFilter">的配置 return null; } //为当前用户设置角色和权限 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roleNames); info.setStringPermissions(permissions); return info; //实际中可能会像上面注释的那样从数据库取得 /* if(null!=currentUsername && "mike".equals(currentUsername)){ //添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色 info.addRole("admin"); //添加权限 info.addStringPermission("admin:manage"); System.out.println("已为用户[mike]赋予了[admin]角色和[admin:manage]权限"); return info; }else{ //若该方法什么都不做直接返回null的话,就会导致任何用户访问/admin/listUser.jsp时都会自动跳转到unauthorizedUrl指定的地址 //详见applicationContext.xml中的<bean id="shiroFilter">的配置 return null; }*/ } /** * 清除所有用户授权信息缓存. * @param principal */ public void clearCachedAuthorizationInfo(String principal) { SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName()); clearCachedAuthorizationInfo(principals); } /** * 将一些数据放到ShiroSession中,以便于其它地方使用 * 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到 */ private void setSession(Object key, Object value){ Subject currentUser = SecurityUtils.getSubject(); if(null != currentUser){ Session session = currentUser.getSession(); System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒"); System.out.println("Session是[" + session.getId() + "]"); if(null != session){ session.setAttribute(key, value); } } } /** * 清除所有用户授权信息缓存 */ public void clearAllCachedAuthorizationInfo() { Cache<Object, AuthorizationInfo> cache = getAuthorizationCache(); if (cache != null) { for (Object key : cache.keys()) { cache.remove(key); } } } // @PostConstruct // public void initCredentialsMatcher() {//MD5加密 // HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(ALGORITHM); // setCredentialsMatcher(matcher); // } }//登录
/** * 用户验证 * @param userlogin * @param model * @return */ @RequestMapping(value = "/loginuser", method = RequestMethod.POST) public String loginuserinfo(Userlogin userlogin, Model model) { System.out.println("-----开始执行验证前------"); String msg = "";//返回信息 String Modleview = "/login";//跳转到登录页面 String username = userlogin.getUsername();// 取得用户名 String password = CipherUtil.generatePassword(userlogin.getPassword());//取得 密码,并用MD5加密 UsernamePasswordToken token = new UsernamePasswordToken(username, password); token.setRememberMe(true); try { System.out.println("-----------验证角色和权限-----------------"); Subject currentUser = SecurityUtils.getSubject(); currentUser.login(token);//验证角色和权限 if (currentUser.isAuthenticated()) { Modleview = "redirect:/homepage";//验证成功 } else { Modleview = "/index";//验证失败 } }catch (IncorrectCredentialsException e) { msg = "登录密码错误. Password for account " + token.getPrincipal() + " was incorrect."; model.addAttribute("message", msg); System.out.println(msg); } catch (ExcessiveAttemptsException e) { msg = "登录失败次数过多"; model.addAttribute("message", msg); System.out.println(msg); } catch (LockedAccountException e) { msg = "帐号已被锁定. The account for username " + token.getPrincipal() + " was locked."; model.addAttribute("message", msg); System.out.println(msg); } catch (DisabledAccountException e) { msg = "帐号已被禁用. The account for username " + token.getPrincipal() + " was disabled."; model.addAttribute("message", msg); System.out.println(msg); } catch (ExpiredCredentialsException e) { msg = "帐号已过期. the account for username " + token.getPrincipal() + " was expired."; model.addAttribute("message", msg); System.out.println(msg); } catch (UnknownAccountException e) { msg = "帐号不存在. There is no user with username of " + token.getPrincipal(); model.addAttribute("message", msg); System.out.println(msg); } catch (UnauthorizedException e) { msg = "您没有得到相应的授权!" + e.getMessage(); model.addAttribute("message", msg); System.out.println(msg); } return Modleview; }
参考文章:
去掉shiro登录时url里的JSESSIONID
我有个maven构建的 springboot+spring+mybatis+shiro+mysql config注解配置的DEMO,如果需要请加群。217114443 进群验证下载,可留可走