代码编织梦想

首先是pom.xml注入依赖包

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

UserShiroRealm

public class UserShiroRealm extends AuthorizingRealm {
    @Autowired
    SysUserService sysUserService;
    @Autowired
    SysRoleService sysRoleService;
    @Autowired
    SysMenuService sysMenuService;

    /**
     * 身份认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.debug("UserShiroRealm.doGetAuthenticationInfo{}", Constants.SHOW_DEBUG_TAG);
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        log.info("验证当前Subject时获取到token为:{}",token.toString());
        //查出是否有此用户
        //获取用户的输入的账号
        String username = token.getUsername();
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        SysUser hasSysUser = sysUserService.getUserByLoginAllInfo(username,null);
//        log.info("hasSysUser:{}",hasSysUser);
        if (hasSysUser == null) {
            没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
            return null;
        }else {
    //            可放在doGetAuthorizationInfo中执行
            // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
//            List<URole> rlist = uRoleDao.findRoleByUid(hasUser.getId());//获取用户角色
//            List<UPermission> plist = uPermissionDao.findPermissionByUid(hasUser.getId());//获取用户权限
//            List<String> roleStrlist=new ArrayList<String>();用户的角色集合
//            List<String> perminsStrlist=new ArrayList<String>();//用户的权限集合
//            for (URole role : rlist) {
//                roleStrlist.add(role.getName());
//            }
//            for (UPermission uPermission : plist) {
//                perminsStrlist.add(uPermission.getName());
//            }
//            hasUser.setRoleStrlist(roleStrlist);
//            hasUser.setPerminsStrlist(perminsStrlist);
        }

        ByteSource credentialsSalt = ByteSource.Util.bytes(hasSysUser.getLoginName()+hasSysUser.getSalt());

        String loginPwd = hasSysUser.getLoginPwd();
        hasSysUser.setLoginPwd("");
        // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
        //此处没有加盐
        //hasSysUser 认证成功的返回信息
        SimpleAuthenticationInfo simpleAuthenticationInfo =
                new SimpleAuthenticationInfo(hasSysUser, loginPwd,credentialsSalt, getName());
        return simpleAuthenticationInfo;
    }



    /**
     * 权限认证
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.debug("UserShiroRealm.doGetAuthorizationInfo{}", "执行Shiro权限认证"+Constants.SHOW_DEBUG_TAG);
        SysUser sysUser = (SysUser) principalCollection.getPrimaryPrincipal();

        //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 管理员拥有所有权限
        if (sysUser.getUserType().equals(0)) {
//        if (false) {
            authorizationInfo.addStringPermission("*:*:*");
        }else {
            if (sysUser != null) {
                //获取用户角色
                List<SysRole> sysUserRoleList =  sysRoleService.getSysRoleInfoUserListForShiro(sysUser.getId());
                for (SysRole r : sysUserRoleList) {
                    authorizationInfo.addRole(r.getRoleKey());
                    //获取用户权限
                    List<SysMenu> sysUserRoleMenuList = sysMenuService.getSysMenuInfoRoleListForShiro(r.getId());
                    for (SysMenu m : sysUserRoleMenuList) {
                        authorizationInfo.addStringPermission(m.getPerms());
                    }
                }
            }
        }
        // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
        return authorizationInfo;
    }

    /**
     * 清理当前缓存权限
     */
    public void clearCachedAuthorizationInfo() {
        log.debug("UserShiroRealm.clearCachedAuthorizationInfo{}", "执行Shiro权限认证"+Constants.SHOW_DEBUG_TAG);
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    /**
     * 重写方法,清除当前用户的的 授权缓存
     * @param principals
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 重写方法,清除当前用户的 认证缓存
     * @param principals
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    /**
     * 自定义方法:清除所有 授权缓存
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    /**
     * 自定义方法:清除所有 认证缓存
     */
    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }
    /**
     * 自定义方法:清除所有的  认证缓存  和 授权缓存
     */
    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }
}

ShiroConfiguration

@Configuration
public class ShiroConfiguration {

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     *
     * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
     * 3、部分过滤器可指定参数,如perms,roles
     *
     */


    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        log.debug("ShiroConfiguration.shiroFilterFactoryBean{}", Constants.SHOW_DEBUG_TAG);

        // 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边
        Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();

        // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        filterChainDefinitionManager.put("/error", "anon");
        filterChainDefinitionManager.put("/static/**", "anon");
        //排除访问swagger
        filterChainDefinitionManager.put( "/swagger-resources/**", "anon");
        filterChainDefinitionManager.put( "/v2/**", "anon");
        filterChainDefinitionManager.put( "/swagger-ui.html/**", "anon");

        filterChainDefinitionManager.put("/webjars/**", "anon");
        filterChainDefinitionManager.put("/index.html", "anon");
        filterChainDefinitionManager.put("/login.html", "anon");

        filterChainDefinitionManager.put("/sys/login/getCaptcha", "anon");

        filterChainDefinitionManager.put("/sys/login", "anon");
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
//        filterChainDefinitionManager.put("/sys/loginOut", "authc");
//        filterChainDefinitionManager.put("/sys/**", "authc");
//        filterChainDefinitionManager.put("/**",  "authc");//其他资源全部拦截,必须通过身份认证成功可通过
        filterChainDefinitionManager.put("/**",  "user");//其他资源全部拦截.身份认证成功或通过记住我均可通过


        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        // 登录成功后要跳转的链接
//        shiroFilterFactoryBean.setSuccessUrl("/home.html");
        // 未授权界面
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        return shiroFilterFactoryBean;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm
        securityManager.setRealm(userShiroRealm());
        //用户授权/认证信息Cache, 采用EhCache 缓存  注入缓存管理器;
        securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;
        securityManager.setRememberMeManager(rememberMeManager());
        //配置自定义session管理,使用ehcache 或redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    //身份认证与权限认证
    @Bean(name = "userShiroRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public UserShiroRealm userShiroRealm() {
        UserShiroRealm userShiroRealm = new UserShiroRealm();

        //缓存开关 setCachingEnabled 管理 setAuthenticationCachingEnabled,setAuthorizationCachingEnabled
        userShiroRealm.setCachingEnabled(false);
        //启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
//        userShiroRealm.setAuthenticationCachingEnabled(false);
        //缓存AuthenticationInfo信息的缓存名称 在ehcache-shiro.xml中有对应缓存的配置
        userShiroRealm.setAuthenticationCacheName("authenticationCache");
        //启用授权缓存,即缓存AuthorizationInfo信息,默认false
//        userShiroRealm.setAuthorizationCachingEnabled(false);
        //缓存AuthorizationInfo信息的缓存名称  在ehcache-shiro.xml中有对应缓存的配置
        userShiroRealm.setAuthorizationCacheName("authorizationCache");

		userShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userShiroRealm;
    }


    /**
     * 凭证匹配器
     * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     ** @return
     */
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher(){
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

		hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
		hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));

		return hashedCredentialsMatcher;
	}

    @Bean(name = "ehCacheManager")
    @DependsOn("lifecycleBeanPostProcessor")
    public EhCacheManager ehCacheManager(){
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return ehCacheManager;
    }

    /**
     * cookie对象;
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
        log.debug("ShiroConfiguration.rememberMeCookie()");
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //如果httyOnly设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击;
//        simpleCookie.setHttpOnly(true);
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(259200);
        //simpleCookie.setMaxAge(20);
        return simpleCookie;
    }

    /**
     * cookie管理对象;
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        log.debug("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        //rememberme cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位),通过以下代码可以获取
        //KeyGenerator keygen = KeyGenerator.getInstance("AES");
        //SecretKey deskey = keygen.generateKey();
        //System.out.println(Base64.encodeToString(deskey.getEncoded()));
        byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");
        cookieRememberMeManager.setCipherKey(cipherKey);
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }



    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 添加ShiroDialect 为了在thymeleaf里使用shiro的标签的bean
     * @return
     */
    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }



    ///附加功能///

    /**
     * 配置session监听
     * @return
     */
    @Bean("sessionListener")
    public ShiroSessionListener sessionListener(){
        ShiroSessionListener sessionListener = new ShiroSessionListener();
        return sessionListener;
    }

    /**
     * 配置会话ID生成器
     * @return
     */
    @Bean
    public SessionIdGenerator sessionIdGenerator() {
        return new JavaUuidSessionIdGenerator();
    }

    /**
     * SessionDAO的作用是为Session提供CRUD并进行持久化的一个shiro组件
     * MemorySessionDAO 直接在内存中进行会话维护
     * EnterpriseCacheSessionDAO  提供了缓存功能的会话维护,默认情况下使用MapCache实现,内部使用ConcurrentHashMap保存缓存的会话。
     * @return
     */
    @Bean
    public SessionDAO sessionDAO() {
        EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
        //使用ehCacheManager
        enterpriseCacheSessionDAO.setCacheManager(ehCacheManager());
        //设置session缓存的名字 默认为 shiro-activeSessionCache
        enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
        //sessionId生成器
        enterpriseCacheSessionDAO.setSessionIdGenerator(sessionIdGenerator());
        return enterpriseCacheSessionDAO;
    }

    /**
     * 配置保存sessionId的cookie
     * 注意:这里的cookie 不是上面的记住我 cookie 记住我需要一个cookie session管理 也需要自己的cookie
     * @return
     */
    @Bean("sessionIdCookie")
    public SimpleCookie sessionIdCookie(){
        //这个参数是cookie的名称
        SimpleCookie simpleCookie = new SimpleCookie("tank-sys");
        //setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:

        //setcookie()的第七个参数
        //设为true后,只能通过http访问,javascript无法访问
        //防止xss读取cookie
        simpleCookie.setHttpOnly(true);
        simpleCookie.setPath("/");
        //maxAge=-1表示浏览器关闭时失效此Cookie
        simpleCookie.setMaxAge(-1);
        return simpleCookie;
    }

    /**
     * 配置会话管理器,设定会话超时及保存
     * @return
     */
    @Bean("sessionManager")
    public SessionManager sessionManager() {

        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        Collection<SessionListener> listeners = new ArrayList<SessionListener>();
        //配置监听
        listeners.add(sessionListener());
        sessionManager.setSessionListeners(listeners);
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setSessionDAO(sessionDAO());
        sessionManager.setCacheManager(ehCacheManager());


        //全局会话超时时间(单位毫秒),默认30分钟  暂时设置为10秒钟 用来测试
        sessionManager.setGlobalSessionTimeout(1800000);
//        sessionManager.setGlobalSessionTimeout(10000);
        //是否开启删除无效的session对象  默认为true
        sessionManager.setDeleteInvalidSessions(true);
        //是否开启定时调度器进行检测过期session 默认为true
//        sessionManager.setSessionValidationSchedulerEnabled(true);
        //设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时
        //设置该属性 就不需要设置 ExecutorServiceSessionValidationScheduler 底层也是默认自动调用ExecutorServiceSessionValidationScheduler
        //暂时设置为 5秒 用来测试
        sessionManager.setSessionValidationInterval(3600000);
//        sessionManager.setSessionValidationInterval(5000);

        //取消url 后面的 JSESSIONID
        sessionManager.setSessionIdUrlRewritingEnabled(false);

        return sessionManager;

    }

}

ShiroSessionListener

public class ShiroSessionListener  implements SessionListener {
    /**
     * 统计在线人数
     * juc包下线程安全自增
     */
    private final AtomicInteger sessionCount = new AtomicInteger(0);

    /**
     * 会话创建时触发
     * @param session
     */
    @Override
    public void onStart(Session session) {
        //会话创建,在线人数加一
        sessionCount.incrementAndGet();
    }

    /**
     * 退出会话时触发
     * @param session
     */
    @Override
    public void onStop(Session session) {
        //会话退出,在线人数减一
        sessionCount.decrementAndGet();
    }

    /**
     * 会话过期时触发
     * @param session
     */
    @Override
    public void onExpiration(Session session) {
        //会话过期,在线人数减一
        sessionCount.decrementAndGet();
    }
    /**
     * 获取在线人数使用
     * @return
     */
    public AtomicInteger getSessionCount() {
        return sessionCount;
    }
}

ShiroUtils

public class ShiroUtils {
    public static Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    public static Session getSession() {
        return SecurityUtils.getSubject().getSession();
    }

    public static void logout() {
        getSubject().logout();
    }

    public static SysUser getSysUser() {
        SysUser user = (SysUser) getSubject().getPrincipal();
        /*if (obj != null) {
            user = new SysUser();
            BeanUtils.copyProperties(user, obj);
        }*/
        return user;
    }

    public static void setSysUser(SysUser user) {
        Subject subject = getSubject();
        PrincipalCollection principalCollection = subject.getPrincipals();
        String realmName = principalCollection.getRealmNames().iterator().next();
        PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(user, realmName);
        // 重新加载Principal
        subject.runAs(newPrincipalCollection);
    }

    public static void clearCachedAuthorizationInfo() {
        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        UserShiroRealm realm = (UserShiroRealm) rsm.getRealms().iterator().next();
        realm.clearCachedAuthorizationInfo();
    }

    public static Long getUserId() {
        Long userId =null;
        Subject subject = getSubject();
        if(subject.isAuthenticated()||subject.isRemembered())
            userId=getSysUser().getId().longValue();
        return  userId;
    }

    public static String getLoginName() {
        return getSysUser().getLoginName();
    }

    public static String getIp() {
        return getSubject().getSession().getHost();
    }

    public static String getSessionId() {
        return String.valueOf(getSubject().getSession().getId());
    }

    /**
     * 生成随机盐
     */
    public static String randomSalt() {
        // 一个Byte占两个字节,此处生成的3字节,字符串长度为6
        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
        String hex = secureRandom.nextBytes(3).toHex();
        return hex;
    }
    public static String getPassword(String name , Object password , String userSalt){
        String hashAlgorithmName = "MD5";
        Object salt = ByteSource.Util.bytes(name+userSalt);
        int hashIterations = 2;
        Object result = new SimpleHash(hashAlgorithmName, password, salt, hashIterations);
        return result.toString();
    }

ehcache-shiro.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">

    <!--
        缓存对象存放路径
        java.io.tmpdir:默认的临时文件存放路径。
        user.home:用户的主目录。
        user.dir:用户的当前工作目录,即当前程序所对应的工作路径。
        其它通过命令行指定的系统属性,如“java –DdiskStore.path=D:\\abc ……”。
    -->
    <diskStore path="java.io.tmpdir"/>


    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="0"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />

    <!-- 授权缓存 -->
    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <!-- 认证缓存 -->
    <cache name="authenticationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <!-- session缓存 -->
    <cache name="shiro-activeSessionCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

</ehcache>

SysLoginController

    @RequestMapping("/login")
    public String login(String loginName, String loginPwd, String captchaCode, boolean rememberMe , HttpServletRequest req, Model model)
    {

        try {
            if(StringUtil.isObjectEmpty(loginName)||StringUtil.isObjectEmpty(loginPwd)){
                model.addAttribute("message", RespCode.RespEnum.SYSUSER_LOGIN_20004.getDescribe());
                return  "login";
            }
            //从session中获取随机数
            String inputStr = captchaCode;
            String random = (String) req.getSession().getAttribute(RandomValidateCodeUtil.RANDOMCODEKEY);
//            if(!captchaCode.equals(random)){//登录麻烦暂去除
            if(false){
                model.addAttribute("message", RespCode.RespEnum.SYSUSER_LOGIN_20005.getDescribe());
                return  "login";
            }
            // 把用户名和密码封装为 UsernamePasswordToken 对象   rememberme   token.setRememberMe(true);
            UsernamePasswordToken token = new UsernamePasswordToken(loginName, loginPwd, rememberMe);
            Subject currentUser = ShiroUtils.getSubject();
            log.info("对用户:{},进行登录验证..验证开始",loginName);

            currentUser.login(token);

            //验证是否登录成功
            if (currentUser.isAuthenticated()) {
                log.info("用户:[{}]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)",loginName);
//                req.getSession().setAttribute(PermissionsConstants.SYSUSER_CONSTANTS.SYS_USER_SESSION,ShiroUtils.getSysUser());
                return "redirect:/sys/home";
            } else {
                token.clear();
                log.info("用户:[{}]登录认证失败,重新登陆",loginName);
                return "login";
            }

        } catch ( UnknownAccountException uae ) {
            log.info("对用户:[{}]进行登录验证..验证失败-username wasn't in the system",loginName);
        } catch ( IncorrectCredentialsException ice ) {
            log.info("对用户:[{}]进行登录验证..验证失败-password didn't match",loginName);
        } catch ( LockedAccountException lae ) {
            log.info("对用户:[{}]进行登录验证..验证失败-account is locked in the system",loginName);
        } catch ( AuthenticationException ae ) {
            log.info("对用户:[{}]进行登录验证..验证失败-password in the system",loginName);
        }catch (Exception e){
            log.info("对用户:[{}]进行登录验证..验证失败-system",loginName);
            e.printStackTrace();
        }
        model.addAttribute("message", RespCode.RespEnum.SYSUSER_LOGIN_20006.getDescribe());
        return "login";
    }
    @PostMapping("/loginOut")
    @ResponseBody
    public RespData loginOut(HttpServletRequest req)
    {
        RespData respData = new RespData();
        try
        {
            ShiroUtils.logout();
            if(StringUtil.isObjectNotEmpty(ShiroUtils.getSysUser()))
                respData.setRespInfo(false,RespCode.RespEnum.FAIL.getCode(), RespCode.RespEnum.FAIL.getDescribe());
            respData.setRespInfo(true,RespCode.RespEnum.SUCCESS.getCode(), RespCode.RespEnum.SUCCESS.getDescribe());
        }
        catch (Exception e)
        {
            respData.setRespInfo(false,RespCode.RespEnum.FAIL.getCode(), RespCode.RespEnum.FAIL.getDescribe());
            e.printStackTrace();
        }
        return respData;
    }

权限控制

    /**
     * 用户列表
     * @param model
     * @return
     */
    @RequiresPermissions("1026902")
    @GetMapping("/index")
    public String index(Model model)
    {
        model.addAttribute("sysStatus_List",PermissionsConstants.SYSSTATUS_MAP());
        return "sys/user/user-index";
    }

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/Andy8921/article/details/106501127

一、Springboot2.3加Mybatis-plus集成Apache Shiro实现权限管理(原生集成)-爱代码爱编程

0、项目结构图 1、pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi

Shiro官方文档超详细解读(二)之会话管理-爱代码爱编程

本篇博客参考Apache Shiro官方文档 本博客参考跟我学Shiro系列文章 本博客接着上一篇博客Shiro官方文档超详细解读(一)编写 一.会话管理Session Management 1.使用Sessions 你通过与当前正在执行的subject进行交互来获得一个会话session: Subject currentUser = Securit

Shiro系列记录(一)—— 你真的懂Shiro么?-爱代码爱编程

1、什么是Shiro Shiro 是 Java 的一个安全框架,它帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。 一张图概括基本功能点: Authentication:身份认证 ,验证用户是否满足登录的条件;Authorization:授权,验证某个已认证的用户是否拥有某个权限;Session Manager:会话管理,即用

SpringBoot11:集成Shiro-爱代码爱编程

Shiro简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。 Shiro是一个开源的java安全(权限)框架,它能够实现身份验证、授权、加密和会话管理等功能。Shiro是ap

Shiro 实战教程(上)-爱代码爱编程

注:该shiro教程来源于B站上的一个教程,由于源码是付费的,我就不分享了,下篇讲解springboot搭配shiro进行使用。 我的个人博客: 天涯志 我的公众号:菜鸟小谢 1.权限的管理 1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者

Shiro 实战教程(下)-爱代码爱编程

注:该shiro教程来源于B站上的一个教程,由于源码是付费的,我就不分享了,下篇讲解springboot搭配shiro进行使用。 我的个人博客: 天涯志 我的公众号:菜鸟小谢 6.整合SpringBoot项目实战 6.0 整合思路 6.1 创建springboot项目 6.2 引入shiro依赖 <dependency