发表于: 2020-08-07 23:07:05

1 2049


shiro案例

1.建表

1.sys_users用户表

2.sys_roles角色表
3.sys_permissions权限表(或资源表)
4.sys_users_roles用户-角色关联表
5.sys_roles_permissions角色-权限关联表(或角色-资源关联表)

登录controller

@Controller
public class LoginController {

/**
    * 用户登录的入口
    *
    * @param username
    * @param password
    * @param model
    * @return
    */
   @RequestMapping("/login")
public String login(
@RequestParam(value = "username", required = false) String username,
           @RequestParam(value = "password", required = false) String password,
           @RequestParam(value = "remember", required = false) String remember,
           Model model) {

System.out.println("登陆用户输入的用户名:" + username + ",密码:" + password);
       String error = null;
       if (username != null && password != null) {
//初始化
           Subject subject = SecurityUtils.getSubject();
           UsernamePasswordToken token = new UsernamePasswordToken(username, password);
           if (remember != null){
if (remember.equals("on")) {
//说明选择了记住我
                   token.setRememberMe(true);
               } else {
token.setRememberMe(false);
               }
}else{
token.setRememberMe(false);
           }

try {
//登录,即身份校验,由通过Spring注入的UserRealm会自动校验输入的用户名和密码在数据库中是否有对应的值
               subject.login(token);
               System.out.println("用户是否登录:" + subject.isAuthenticated());
               return "redirect:index.do";
           } catch (UnknownAccountException e) {
e.printStackTrace();
               error = "用户账户不存在,错误信息:" + e.getMessage();
           } catch (IncorrectCredentialsException e) {
e.printStackTrace();
               error = "用户名或密码错误,错误信息:" + e.getMessage();
           } catch (LockedAccountException e) {
e.printStackTrace();
               error = "该账号已锁定,错误信息:" + e.getMessage();
           } catch (DisabledAccountException e) {
e.printStackTrace();
               error = "该账号已禁用,错误信息:" + e.getMessage();
           } catch (ExcessiveAttemptsException e) {
e.printStackTrace();
               error = "该账号登录失败次数过多,错误信息:" + e.getMessage();
           } catch (Exception e){
e.printStackTrace();
               error = "未知错误,错误信息:" + e.getMessage();
           }
} else {
error = "请输入用户名和密码";
       }
//登录失败,跳转到login页面
       model.addAttribute("error", error);
       return "login";
   }

//    /**
//     * 退出登录,我们不需要实现,ShiroFilter过滤器会帮我们生成一个logout请求,
//     *    当浏览器访问`/logout`请求时,Shiro会自动清空缓存并重定向到配置好的loginUrl页面
//     *
//     * @return
//     */
//    @RequestMapping("/logout")
//    public String logout() {
//        Subject subject = SecurityUtils.getSubject();
//        subject.logout();
//        return "index";
//    }

   /**
    * 登录成功,跳转到首页
    *
    * @return
    */
   @RequestMapping("/index")
public String index() {
return "index";
   }
}

权限异常

@ControllerAdvice
public class DefaultExceptionHandler {

/**
    * 权限校验失败异常
    * @param request
    * @param e
    * @return
    */
   @ExceptionHandler({UnauthorizedException.class})
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) {
ModelAndView mv = new ModelAndView();
       mv.addObject("exception", e);
       mv.setViewName("unauthorized");
       return mv;
   }
}

修改spring-shiro-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:util="http://www.springframework.org/schema/util"
      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.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

   <!-- 缓存管理器 使用Ehcache实现 -->
   <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
       <property name="cacheManagerConfigFile" value="classpath:other/ehcache.xml"/>
   </bean>

   <!-- 凭证匹配器 -->
   <bean id="credentialsMatcher" class="cn.tycoding.credentials.RetryLimitHashedCredentialsMatcher">
       <!-- 使用Spring构造器注入cacheManager -->
       <constructor-arg ref="cacheManager"/>
       <!-- 指定散列算法名称 -->
       <property name="hashAlgorithmName" value="md5"/>
       <!-- 指定散列迭代的次数 -->
       <property name="hashIterations" value="2"/>
       <!-- 是否储存散列后的密码为16进制,需要和生成密码时的一样,默认是base64 -->
       <property name="storedCredentialsHexEncoded" value="true"/>
   </bean>

   <!-- Realm实现 -->
   <bean id="userRealm" class="cn.tycoding.realm.UserRealm">
       <!-- 使用credentialsMatcher实现密码验证服务 -->
       <property name="credentialsMatcher" ref="credentialsMatcher"/>
       <!-- 是否启用缓存 -->
       <property name="cachingEnabled" value="true"/>
       <!-- 是否启用身份验证缓存 -->
       <property name="authenticationCachingEnabled" value="true"/>
       <!-- 缓存AuthenticationInfo信息的缓存名称 -->
       <property name="authenticationCacheName" value="authenticationCache"/>
       <!-- 是否启用授权缓存,缓存AuthorizationInfo信息 -->
       <property name="authorizationCachingEnabled" value="true"/>
       <!-- 缓存AuthorizationInfo信息的缓存名称 -->
       <property name="authorizationCacheName" value="authorizationCache"/>
   </bean>

   <!-- 会话ID生成器,用于生成会话的ID,使用JavaScriptUUID生成 -->
   <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>

   <!-- 会话Cookie模板 -->
   <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
       <constructor-arg value="sid"/>
       <!-- 如果设置为true,则客户端不会暴露给服务端脚本代码,有助于减少某些类型的跨站脚本攻击 -->
       <property name="httpOnly" value="true"/>
       <property name="maxAge" value="-1"/><!-- maxAge=-1表示浏览器关闭时失效此Cookie -->
   </bean>
   <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
       <constructor-arg value="rememberMe"/>
       <property name="httpOnly" value="true"/>
       <property name="maxAge" value="2592000"/><!-- 30-->
   </bean>

   <!-- rememberMe管理器 -->
   <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
       <!-- cipherKey是加密rememberMe Cookie的密匙,默认AES算法 -->
       <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
       <property name="cookie" ref="rememberMeCookie"/>
   </bean>

   <!-- 会话DAO -->
   <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
       <!-- 设置session缓存的名称,默认就是shiro-activeSessionCache -->
       <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
       <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
   </bean>

   <!-- 会话验证调度器 -->
   <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
       <property name="sessionValidationInterval" value="1800000"/>
       <property name="sessionManager" ref="sessionManager"/>
   </bean>

   <!-- 会话管理器 -->
   <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
       <!-- 设置全局会话过期时间:默认30分钟 -->
       <property name="globalSessionTimeout" value="1800000"/>
       <!-- 是否自动删除无效会话 -->
       <property name="deleteInvalidSessions" value="true"/>
       <!-- 会话验证是否启用 -->
       <property name="sessionValidationSchedulerEnabled" value="true"/>
       <!-- 会话验证调度器 -->
       <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
       <!-- 会话持久化sessionDao -->
       <property name="sessionDAO" ref="sessionDAO"/>
       <!-- 是否启用sessionIdCookie,默认是启用的 -->
       <property name="sessionIdCookieEnabled" value="true"/>
       <!-- 会话Cookie -->
       <property name="sessionIdCookie" ref="sessionIdCookie"/>
   </bean>

   <!-- 安全管理器 -->
   <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
       <property name="realm" ref="userRealm"/>
       <property name="sessionManager" ref="sessionManager"/>
       <property name="cacheManager" ref="cacheManager"/>
       <!-- 设置securityManager安全管理器的rememberMeManger -->
       <property name="rememberMeManager" ref="rememberMeManager"/>
   </bean>

   <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
   <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
       <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
       <property name="arguments" ref="securityManager"/>
   </bean>

   <!-- 基于Form表单的身份验证过滤器 -->
   <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
       <!-- 这两个字段,usernamepassword要和表单中定义的usernamepassword字段名称相同,可以更改,但是表单和XML要对应 -->
       <property name="usernameParam" value="username"/>
       <property name="passwordParam" value="password"/>
       <property name="loginUrl" value="/login.jsp"/>
       <!-- rememberMeParamrememberMe请求参数名,请求参数是boolean类型,true表示记住我 -->
       <property name="rememberMeParam" value="rememberMe"/>
   </bean>

   <!-- ShiroWeb过滤器 -->
   <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
       <!-- Shiro的安全管理器,所有关于安全的操作都会经过SecurityManager -->
       <property name="securityManager" ref="securityManager"/>
       <!-- 系统认证提交地址,如果用户退出即session丢失就会访问这个页面 -->
       <property name="loginUrl" value="/login.jsp"/>
       <!-- 登录成功后重定向的地址,不建议配置 -->
       <!--<property name="successUrl" value="/index.do"/>-->
       <!-- 权限验证失败跳转的页面,需要配合SpringExceptionHandler异常处理机制使用 -->
       <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
       <property name="filters">
           <util:map>
               <entry key="authc" value-ref="formAuthenticationFilter"/>
           </util:map>
       </property>
       <!-- 自定义的过滤器链,从上向下执行,一般将`/**`放到最下面 -->
       <property name="filterChainDefinitions">
           <value>

               <!-- 静态资源不拦截 -->
               /static/** = anon
/lib/** = anon
/js/** = anon

<!-- 登录页面不拦截 -->
               /login.jsp = anon
/login.do = anon


<!-- Shiro提供了退出登录的配置`logout`,会生成路径为`/logout`的请求地址,访问这个地址即会退出当前账户并清空缓存 -->
               /logout = logout

<!-- user表示身份通过或通过记住我通过的用户都能访问系统 -->
               /index.jsp = user

<!-- authc表示访问该地址用户必须身份验证通过,即Subject.isAuthenticated() == true -->
               /authenticated.jsp = authc

<!-- `/**`表示所有请求,表示访问该地址的用户是身份验证通过或RememberMe登录的都可以 -->
               /** = user

</value>
       </property>
   </bean>

   <!-- Shiro生命周期处理器-->
   <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

</beans>

明天任务 完成shiro剩下的内容


返回列表 返回列表
评论

    分享到