您的位置:1010cc时时彩经典版 > 1010cc时时彩经典版 > 【1010cc时时彩经典版】Boot项目利用Redis实现sess

【1010cc时时彩经典版】Boot项目利用Redis实现sess

发布时间:2019-08-12 16:57编辑:1010cc时时彩经典版浏览(160)

    七、spring boot 1.5.4 集成shiro cas,完结单点登入和权力决定,1.5.4shiro

    1.增添maven依赖(先安装好cas-server-3.5.2,安装步骤请查看本文参照他事他说加以考察作品)

            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.2.4</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.2.4</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-cas</artifactId>
                <version>1.2.4</version>
            </dependency>        
    

     2.起步累加多@ServletComponentScan注明

    @SpringBootApplication
    public class Application {
    
        /**
         * main function
         * @param args params
         */
        public static void main(String[] args){
            ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
    
            //test if a xml bean inject into springcontext successful
            User user = (User)context.getBean("user1");
            System.out.println(JSONObject.toJSONString(user));
        }
    }
    

     

     3.配置shiro cas

    package com.hdwang.config.shiroCas;
    
    import com.hdwang.dao.UserDao;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.cas.CasFilter;
    import org.apache.shiro.cas.CasSubjectFactory;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.filter.authc.LogoutFilter;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.jasig.cas.client.session.SingleSignOutFilter;
    import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.web.filter.DelegatingFilterProxy;
    
    import javax.servlet.Filter;
    import javax.servlet.annotation.WebListener;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    /**
     * Created by hdwang on 2017/6/20.
     * shiro cas 配置
     */
    @Configuration
    public class ShiroCasConfiguration {
    
        private static final Logger logger = LoggerFactory.getLogger(ShiroCasConfiguration.class);
    
        // cas server地址
        public static final String casServerUrlPrefix = "https://localhost:8443/cas";
        // Cas登录页面地址
        public static final String casLoginUrl = casServerUrlPrefix   "/login";
        // Cas登出页面地址
        public static final String casLogoutUrl = casServerUrlPrefix   "/logout";
        // 当前工程对外提供的服务地址
        public static final String shiroServerUrlPrefix = "http://localhost:8081";
        // casFilter UrlPattern
        public static final String casFilterUrlPattern = "/cas";
        // 登录地址
        public static final String loginUrl = casLoginUrl   "?service="   shiroServerUrlPrefix   casFilterUrlPattern;
        // 登出地址
        public static final String logoutUrl = casLogoutUrl "?service=" shiroServerUrlPrefix;
        // 登录成功地址
        public static final String loginSuccessUrl = "/home";
        // 权限认证失败跳转地址
        public static final String unauthorizedUrl = "/error/403.html";
    
    
        @Bean
        public EhCacheManager getEhCacheManager() {
            EhCacheManager em = new EhCacheManager();
            em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
            return em;
        }
    
        @Bean(name = "myShiroCasRealm")
        public MyShiroCasRealm myShiroCasRealm(EhCacheManager cacheManager) {
            MyShiroCasRealm realm = new MyShiroCasRealm();
            realm.setCacheManager(cacheManager);
            //realm.setCasServerUrlPrefix(ShiroCasConfiguration.casServerUrlPrefix);
            // 客户端回调地址
            //realm.setCasService(ShiroCasConfiguration.shiroServerUrlPrefix   ShiroCasConfiguration.casFilterUrlPattern);
            return realm;
        }
    
        /**
         * 注册单点登出listener
         * @return
         */
        @Bean
        public ServletListenerRegistrationBean singleSignOutHttpSessionListener(){
            ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean();
            bean.setListener(new SingleSignOutHttpSessionListener());
    //        bean.setName(""); //默认为bean name
            bean.setEnabled(true);
            //bean.setOrder(Ordered.HIGHEST_PRECEDENCE); //设置优先级
            return bean;
        }
    
        /**
         * 注册单点登出filter
         * @return
         */
        @Bean
        public FilterRegistrationBean singleSignOutFilter(){
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setName("singleSignOutFilter");
            bean.setFilter(new SingleSignOutFilter());
            bean.addUrlPatterns("/*");
            bean.setEnabled(true);
            //bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
            return bean;
        }
    
    
    
        /**
         * 注册DelegatingFilterProxy(Shiro)
         *
         * @return
         * @author SHANHY
         * @create  2016年1月13日
         */
        @Bean
        public FilterRegistrationBean delegatingFilterProxy() {
            FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
            filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
            //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
            filterRegistration.addInitParameter("targetFilterLifecycle", "true");
            filterRegistration.setEnabled(true);
            filterRegistration.addUrlPatterns("/*");
            return filterRegistration;
        }
    
    
        @Bean(name = "lifecycleBeanPostProcessor")
        public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean
        public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
            daap.setProxyTargetClass(true);
            return daap;
        }
    
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(MyShiroCasRealm myShiroCasRealm) {
            DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
            dwsm.setRealm(myShiroCasRealm);
    //      <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
            dwsm.setCacheManager(getEhCacheManager());
            // 指定 SubjectFactory
            dwsm.setSubjectFactory(new CasSubjectFactory());
            return dwsm;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
            aasa.setSecurityManager(securityManager);
            return aasa;
        }
    
    
        /**
         * CAS过滤器
         *
         * @return
         * @author SHANHY
         * @create  2016年1月17日
         */
        @Bean(name = "casFilter")
        public CasFilter getCasFilter() {
            CasFilter casFilter = new CasFilter();
            casFilter.setName("casFilter");
            casFilter.setEnabled(true);
            // 登录失败后跳转的URL,也就是 Shiro 执行 CasRealm 的 doGetAuthenticationInfo 方法向CasServer验证tiket
            casFilter.setFailureUrl(loginUrl);// 我们选择认证失败后再打开登录页面
            return casFilter;
        }
    
        /**
         * ShiroFilter<br/>
         * 注意这里参数中的 StudentService 和 IScoreDao 只是一个例子,因为我们在这里可以用这样的方式获取到相关访问数据库的对象,
         * 然后读取数据库相关配置,配置到 shiroFilterFactoryBean 的访问规则中。实际项目中,请使用自己的Service来处理业务逻辑。
         *
         * @param securityManager
         * @param casFilter
         * @param userDao
         * @return
         * @author SHANHY
         * @create  2016年1月14日
         */
        @Bean(name = "shiroFilter")
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager, CasFilter casFilter, UserDao userDao) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            // 必须设置 SecurityManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
            shiroFilterFactoryBean.setLoginUrl(loginUrl);
            // 登录成功后要跳转的连接
            shiroFilterFactoryBean.setSuccessUrl(loginSuccessUrl);
            shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
            // 添加casFilter到shiroFilter中
            Map<String, Filter> filters = new HashMap<>();
            filters.put("casFilter", casFilter);
           // filters.put("logout",logoutFilter());
            shiroFilterFactoryBean.setFilters(filters);
    
            loadShiroFilterChain(shiroFilterFactoryBean, userDao);
            return shiroFilterFactoryBean;
        }
    
        /**
         * 加载shiroFilter权限控制规则(从数据库读取然后配置),角色/权限信息由MyShiroCasRealm对象提供doGetAuthorizationInfo实现获取来的
         *
         * @author SHANHY
         * @create  2016年1月14日
         */
        private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean, UserDao userDao){
            /////////////////////// 下面这些规则配置最好配置到配置文件中 ///////////////////////
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    
            // authc:该过滤器下的页面必须登录后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
            // anon: 可以理解为不拦截
            // user: 登录了就不拦截
            // roles["admin"] 用户拥有admin角色
            // perms["permission1"] 用户拥有permission1权限
            // filter顺序按照定义顺序匹配,匹配到就验证,验证完毕结束。
            // url匹配通配符支持:? * **,分别表示匹配1个,匹配0-n个(不含子路径),匹配下级所有路径
    
            //1.shiro集成cas后,首先添加该规则
            filterChainDefinitionMap.put(casFilterUrlPattern, "casFilter");
            //filterChainDefinitionMap.put("/logout","logout"); //logut请求采用logout filter
    
            //2.不拦截的请求
            filterChainDefinitionMap.put("/css/**","anon");
            filterChainDefinitionMap.put("/js/**","anon");
            filterChainDefinitionMap.put("/login", "anon");
            filterChainDefinitionMap.put("/logout","anon");
            filterChainDefinitionMap.put("/error","anon");
            //3.拦截的请求(从本地数据库获取或者从casserver获取(webservice,http等远程方式),看你的角色权限配置在哪里)
            filterChainDefinitionMap.put("/user", "authc"); //需要登录
            filterChainDefinitionMap.put("/user/add/**", "authc,roles[admin]"); //需要登录,且用户角色为admin
            filterChainDefinitionMap.put("/user/delete/**", "authc,perms["user:delete"]"); //需要登录,且用户有权限为user:delete
    
            //4.登录过的不拦截
            filterChainDefinitionMap.put("/**", "user");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        }
    
    }
    
    package com.hdwang.config.shiroCas;
    
    import javax.annotation.PostConstruct;
    
    import com.hdwang.dao.UserDao;
    import com.hdwang.entity.User;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.cas.CasRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * Created by hdwang on 2017/6/20.
     * 安全数据源
     */
    public class MyShiroCasRealm extends CasRealm{
    
        private static final Logger logger = LoggerFactory.getLogger(MyShiroCasRealm.class);
    
        @Autowired
        private UserDao userDao;
    
        @PostConstruct
        public void initProperty(){
    //      setDefaultRoles("ROLE_USER");
            setCasServerUrlPrefix(ShiroCasConfiguration.casServerUrlPrefix);
            // 客户端回调地址
            setCasService(ShiroCasConfiguration.shiroServerUrlPrefix   ShiroCasConfiguration.casFilterUrlPattern);
        }
    
    //    /**
    //     * 1、CAS认证 ,验证用户身份
    //     * 2、将用户基本信息设置到会话中(不用了,随时可以获取的)
    //     */
    //    @Override
    //    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
    //
    //        AuthenticationInfo authc = super.doGetAuthenticationInfo(token);
    //
    //        String account = (String) authc.getPrincipals().getPrimaryPrincipal();
    //
    //        User user = userDao.getByName(account);
    //        //将用户信息存入session中
    //        SecurityUtils.getSubject().getSession().setAttribute("user", user);
    //
    //        return authc;
    //    }
    
        /**
         * 权限认证,为当前登录的Subject授予角色和权限
         * @see 经测试:本例中该方法的调用时机为需授权资源被访问时
         * @see 经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例中默认并未启用AuthorizationCache
         * @see 经测试:如果连续访问同一个URL(比如刷新),该方法不会被重复调用,Shiro有一个时间间隔(也就是cache时间,在ehcache-shiro.xml中配置),超过这个时间间隔再刷新页面,该方法会被执行
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            logger.info("##################执行Shiro权限认证##################");
            //获取当前登录输入的用户名,等价于(String) principalCollection.fromRealm(getName()).iterator().next();
            String loginName = (String)super.getAvailablePrincipal(principalCollection);
    
            //到数据库查是否有此对象(1.本地查询 2.可以远程查询casserver 3.可以由casserver带过来角色/权限其它信息)
            User user=userDao.getByName(loginName);// 实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
            if(user!=null){
                //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
                SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
                //给用户添加角色(让shiro去验证)
                Set<String> roleNames = new HashSet<>();
                if(user.getName().equals("boy5")){
                    roleNames.add("admin");
                }
                info.setRoles(roleNames);
    
                if(user.getName().equals("李四")){
                    //给用户添加权限(让shiro去验证)
                    info.addStringPermission("user:delete");
                }
    
    
                // 或者按下面这样添加
                //添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
    //            simpleAuthorInfo.addRole("admin");
                //添加权限
    //            simpleAuthorInfo.addStringPermission("admin:manage");
    //            logger.info("已为用户[mike]赋予了[admin]角色和[admin:manage]权限");
                return info;
            }
            // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
            return null;
        }
    
    }
    
    package com.hdwang.controller;
    
    import com.hdwang.config.shiroCas.ShiroCasConfiguration;
    import com.hdwang.entity.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import javax.servlet.http.HttpSession;
    
    /**
     * Created by hdwang on 2017/6/21.
     * 跳转至cas server去登录(一个入口)
     */
    @Controller
    @RequestMapping("")
    public class CasLoginController {
    
        /**
         * 一般用不到
         * @param model
         * @return
         */
        @RequestMapping(value="/login",method= RequestMethod.GET)
        public String loginForm(Model model){
            model.addAttribute("user", new User());
    //      return "login";
            return "redirect:"   ShiroCasConfiguration.loginUrl;
        }
    
    
        @RequestMapping(value = "logout", method = { RequestMethod.GET,
                RequestMethod.POST })
        public String loginout(HttpSession session)
        {
            return "redirect:" ShiroCasConfiguration.logoutUrl;
        }
    }
    
    package com.hdwang.controller;
    
    import com.alibaba.fastjson.JSONObject;
    import com.hdwang.entity.User;
    import com.hdwang.service.datajpa.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.mgt.SecurityManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    /**
     * Created by hdwang on 2017/6/19.
     */
    @Controller
    @RequestMapping("/home")
    public class HomeController {
    
        @Autowired
        UserService userService;
    
        @RequestMapping("")
        public String index(HttpSession session, ModelMap map, HttpServletRequest request){
    //        User user = (User) session.getAttribute("user");
    
            System.out.println(request.getUserPrincipal().getName());
            System.out.println(SecurityUtils.getSubject().getPrincipal());
    
            User loginUser = userService.getLoginUser();
            System.out.println(JSONObject.toJSONString(loginUser));
    
            map.put("user",loginUser);
            return "home";
        }
    
    
    
    }
    

     4.周转验证

    登录 

    访问:

    跳转至:

    输入精确用户名密码登陆跳转回:

    最后跳回:

     

    登出

    访问:

    跳转至:

    鉴于未登入,又实践登入步骤,所以最终回到

    此番报到成功后赶回:

     

    cas server端登出(也行)

    访问:

    再访问: 会跳转至登陆页,perfect!

     

    参照文章

    1.

    2.

    3.

    4.

    5.

     

    boot 1.5.4 集成shiro cas,达成单点登陆和权杖调整,1.5.4shiro 1.增加maven正视(先安装好cas-server-3.5.2,安装步骤请查看本文参谋小说)...

    1.安装cas-server-3.5.2

    在今世互联网服务中,session(会话)不得不说是特别关键也是不容置疑要贯彻的定义,因而在web后台开采中,对session的管制和保卫安全是供给求促成的零件。那篇作品主要是介绍怎样在Spring Boot项目中投入redis来兑现对session的仓库储存与治本。

    4 源码分析

    有非常短一段时间都认为本人加多个filter,基于RBAC模型,就会很自在的落实权力调节,没须求引进shiro,spring-security那样的框架扩展系统的复杂度。事实上也真正如此,要是您的供给仅仅是决定用户能或不能够访谈有些url,使用框架和投机完成filter效果基本一致,不一致在于应用shiro和spring-security可以提供越来越多的扩大,集成了好多实用的功效,全体布局特别正规。shiro和spring-security有怎么样更加的多职能,这里不再进行,感兴趣的校友能够自行百度,我们这里以shiro为例,陈述spring-boot项目怎么结合shiro达成权力调控。

    官网:

    1. 利用Spring Initializr来新建二个spring boot项目

    4.1 Server源码剖析

    Cas server端选择Spring WebFlow来张开流程序调节制,由此本文以连串webflow文件为切入点,对流程相关源码举行辨析。Cas系统的webflow文件位于WEB-INF/webflow目录下,分为登入流程和刊登流程。

    1、添加maven依赖

    <!--shiro-core --><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.3.2</version></dependency><!-- 整合ehcache,减少数据库查询次数 --><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version></dependency>
    

    下载地址:cas-server-3.5.2-release.zip

    1010cc时时彩经典版 1

    4.1.1 登入流程解析

    2、添加shiro配置

    创建ShiroConfigration.java

    @Configurationpublic class ShiroConfigration { private static final Logger logger = LoggerFactory.getLogger(ShiroConfigration.class); private static Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); @Bean public SimpleCookie rememberMeCookie() { SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); simpleCookie.setMaxAge(7 * 24 * 60 * 60);//保存10天 return simpleCookie; } /** * cookie管理对象; */ @Bean public CookieRememberMeManager rememberMeManager() { logger.debug("ShiroConfiguration.rememberMeManager; CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie; cookieRememberMeManager.setCipherKey(Base64.decode("kPv59vyqzj00x11LXJZTjJ2UHW48jzHN")); return cookieRememberMeManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy("shiroFilter"); // 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 proxy.setTargetFilterLifecycle; filterRegistration.setFilter; filterRegistration.setEnabled; //filterRegistration.addUrlPatterns;// 可以自己灵活的定义很多,避免一些根本不需要被Shiro处理的请求被包含进来 return filterRegistration; } @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } @Bean(name="securityManager") public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(myShiroRealm; manager.setRememberMeManager(rememberMeManager; manager.setCacheManager(ehCacheManager; return manager; } /** * ShiroFilterFactoryBean 处理拦截资源文件问题。 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager * <p> * Filter Chain定义说明 * 1、一个URL可以配置多个Filter,使用逗号分隔 * 2、当设置多个过滤器时,全部验证通过,才视为通过 * 3、部分过滤器可指定参数,如perms,roles */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean getShiroFilterFactoryBean() { logger.debug("ShiroConfigration.getShiroFilterFactoryBean; ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager; HashMap<String, javax.servlet.Filter> loginFilter = new HashMap<>(); loginFilter.put("loginFilter", new LoginFilter; shiroFilterFactoryBean.setFilters(loginFilter); filterChainDefinitionMap.put("/login/submit", "anon"); filterChainDefinitionMap.put("/logout", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/test/**", "anon"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl; //配置记住我或认证通过可以访问的地址 filterChainDefinitionMap.put("/", "user"); //未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/unauth"); filterChainDefinitionMap.put("/**", "loginFilter"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * shiro缓存管理器; * 需要注入对应的其它的实体类中: * 1、安全管理器:securityManager * 可见securityManager是整个shiro的核心; * * @return */ @Bean public EhCacheManager ehCacheManager() { EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); return cacheManager; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; }}
    

    shiroFilter是布局的首要,

    • anon表示同意无名氏访问
    • shiroFilterFactoryBean.setFilters(loginFilter)来设置自定义的过滤器,如本处设置了LoginFilter用于添Garden录拦截
    • filterChainDefinitionMap.put("/**", "loginFilter");用于钦定loginFilter的成效范围

    安装参谋小说:

    2. 在pom.xml中增加redis和session的连带重视。项目转移的时候即便也会自动生成父注重,不过1.5.3版本的spring boot的redis相关注重有极大大概或不能健康干活,作者自行在maven repository找到了相比较牢固的版本如下方代码所示

    4.1.1.1 访谈接入Cas系统的选取种类Client1

    登入流程布置文件为login-webflow.xm。
    浏览器首次访谈配置了单点登入的施用种类时(http://www.client1.com/index),Client1会将呼吁重定向到cas系统
    (http://www.casserver.com/serviceValidate?service=http://www.client1.com/index)
    cas系统接受到浏览器发来的恳求,整个报到流程从此处发轫,流程早先化。
    WEB-INF/login-webflow.xml部分代码:

     <on-start>
            <evaluate expression="initialFlowSetupAction"/>
        </on-start>
    

    开端化部分会调用InitialFlowSetupAction类的doExecute方法,假设有异乎常常须要,能够在此办法中扩充对应的逻辑。
    InitialFlowSetupAction的doExecute方法:

    @Override
        protected Event doExecute(final RequestContext context) throws Exception {
            final HttpServletRequest request = WebUtils.getHttpServletRequest(context);
    
            final String contextPath = context.getExternalContext().getContextPath();
            final String cookiePath = StringUtils.isNotBlank(contextPath) ? contextPath   '/' : "/";
    
            if (StringUtils.isBlank(warnCookieGenerator.getCookiePath())) {
                logger.info("Setting path for cookies for warn cookie generator to: {} ", cookiePath);
                this.warnCookieGenerator.setCookiePath(cookiePath);
            } else {
                logger.debug("Warning cookie path is set to {} and path {}", warnCookieGenerator.getCookieDomain(),
                        warnCookieGenerator.getCookiePath());
            }
            if (StringUtils.isBlank(ticketGrantingTicketCookieGenerator.getCookiePath())) {
                logger.info("Setting path for cookies for TGC cookie generator to: {} ", cookiePath);
                this.ticketGrantingTicketCookieGenerator.setCookiePath(cookiePath);
            } else {
                logger.debug("TGC cookie path is set to {} and path {}", ticketGrantingTicketCookieGenerator.getCookieDomain(),
                        ticketGrantingTicketCookieGenerator.getCookiePath());
            }
    //将TGT放在FlowScope作用域中 
            WebUtils.putTicketGrantingTicketInScopes(context,
                    this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request));
    //将warnCookieValue放在FlowScope作用域中
            WebUtils.putWarningCookie(context,
                    Boolean.valueOf(this.warnCookieGenerator.retrieveCookieValue(request)));
    //获取service参数
            final Service service = WebUtils.getService(this.argumentExtractors, context);
    
    
            if (service != null) {
                logger.debug("Placing service in context scope: [{}]", service.getId());
    
                final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
                if (registeredService != null && registeredService.getAccessStrategy().isServiceAccessAllowed()) {
                    logger.debug("Placing registered service [{}] with id [{}] in context scope",
                            registeredService.getServiceId(),
                            registeredService.getId());
                    WebUtils.putRegisteredService(context, registeredService);
    
                    final RegisteredServiceAccessStrategy accessStrategy = registeredService.getAccessStrategy();
                    if (accessStrategy.getUnauthorizedRedirectUrl() != null) {
                        logger.debug("Placing registered service's unauthorized redirect url [{}] with id [{}]in context scope",
                                accessStrategy.getUnauthorizedRedirectUrl(),
                                registeredService.getServiceId());
                        WebUtils.putUnauthorizedRedirectUrl(context, accessStrategy.getUnauthorizedRedirectUrl());
                    }
                }
            } else if (!this.enableFlowOnAbsentServiceRequest) {
                logger.warn("No service authentication request is available at [{}]. CAS is configured to disable the flow.",
                        WebUtils.getHttpServletRequest(context).getRequestURL());
                throw new NoSuchFlowExecutionException(context.getFlowExecutionContext().getKey(),
                        new UnauthorizedServiceException("screen.service.required.message", "Service is required"));
            }
    //将service放在FlowScope作用域中 
            WebUtils.putService(context, service);
            return result("success");
        }
    

    InitialFlowSetupAction的doExecute要做的就是把ticketGrantingTicketId,warnCookieValue和service放到FlowScope的功力域中,以便在签到流程中的state中开始展览判定。起先化达成后,登入流程流转到第叁个state(ticketGrantingTicketExistsCheck)。

    <action-state id="ticketGrantingTicketCheck">
            <evaluate expression="ticketGrantingTicketCheckAction"/>
            <transition on="notExists" to="gatewayRequestCheck"/>
            <transition on="invalid" to="terminateSession"/>
            <transition on="valid" to="hasServiceCheck"/>
        </action-state>
    

    ticketGrantingTicketCheckAction的doExecute方法决断request的Cookie中是或不是带走有效的TGT,第3回访谈时并未有辅导TGT,流程跳转到gatewayRequestCheck。

    <decision-state id="gatewayRequestCheck">
            <if test="requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null"
                then="gatewayServicesManagementCheck" else="serviceAuthorizationCheck"/>
        </decision-state>
    

    因为初叶化时,纵然把service保存在了FlowScope成效域中,但request中的参数gateway荒诞不经,登入流程流转到第二个state(serviceAuthorizationCheck)。

     <action-state id="serviceAuthorizationCheck">
            <evaluate expression="serviceAuthorizationCheck"/>
            <transition to="initializeLogin"/>
        </action-state>
    

    ServiceAuthorizationCheck的doExecute方法,要做的正是推断FlowScope成效域中是或不是留存service,假设service存在,查找service的注册新闻。登入流程流转到第多个state(generateLoginTicket)。

      <action-state id="initializeLogin">
            <evaluate expression="'success'"/>
            <transition on="success" to="viewLoginForm"/>
        </action-state>
    

    initializeLogin不做判别,存在只是为着合营旧cas版本。直接跳转到viewLoginForm。

    <view-state id="viewLoginForm" view="casLoginView" model="credential">
            <binder>
                <binding property="username" required="true"/>
                <binding property="password" required="true"/>
            </binder>
            <on-entry>
                <set name="viewScope.commandName" value="'credential'"/>
            </on-entry>
            <transition on="submit" bind="true" validate="true" to="realSubmit"/>
        </view-state>
    

    那会儿流转到CAS单点登陆服务器端的报到页面casLoginView.jsp。

    <action-state id="realSubmit">
            <evaluate
                    expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credential, messageContext)"/>
            <transition on="warn" to="warn"/>
            <transition on="success" to="sendTicketGrantingTicket"/>
            <transition on="successWithWarnings" to="showMessages"/>
            <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
            <transition on="error" to="initializeLogin"/>
        </action-state>
    

    用户在签到页面输入账号密码提交后,流程走到realSumit。
    authenticationViaFormAction类的submit()对用户提交的表明音信进行表明。

    public final Event submit(final RequestContext context, final Credential credential,
                                  final MessageContext messageContext)  {
            //判断是否是已登录过,请求ST的
            if (isRequestAskingForServiceTicket(context)) {
                  //如果已登录,则生成ST
    return grantServiceTicket(context, credential);
            }
           //未登陆过,生成TGT
            return createTicketGrantingTicket(context, credential, messageContext);
        }
    

    注解成功则跳转到sendTicketGrantingTicket。

    <action-state id="sendTicketGrantingTicket">
            <evaluate expression="sendTicketGrantingTicketAction"/>
            <transition to="serviceCheck"/>
        </action-state>
    

    进而跳转到serviceCheck

    <decision-state id="serviceCheck">
            <if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess"/>
        </decision-state>
    

    剖断是或不是是由使用页面跳转到登陆页面登入的,若是是,则跳转到generateServiceTicket,不是则跳转到viewGenericLoginSuccess。
    此处我们跳转到generateServiceTicket

     <action-state id="generateServiceTicket">
            <evaluate expression="generateServiceTicketAction"/>
            <transition on="success" to="warn"/>
            <transition on="unregisteredService" to="viewGenericLoginSuccess"/>
            <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
            <transition on="error" to="initializeLogin"/>
            <transition on="gateway" to="gatewayServicesManagementCheck"/>
        </action-state>
    

    generateServiceTicketAction类的doExecute方法生成ST,并跳转到warn

     <decision-state id="warn">
            <if test="flowScope.warnCookieValue" then="showWarningView" else="redirect"/>
        </decision-state>
    

    跳转到redirect

     <action-state id="redirect">
            <evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)"
                      result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response"/>
            <transition to="postRedirectDecision"/>
    </action-state>
    
        <decision-state id="postRedirectDecision">
            <if test="requestScope.response.responseType.name() == 'POST'" then="postView" else="redirectView"/>
    </decision-state>
    
        <end-state id="redirectView" view="externalRedirect:#{requestScope.response.url}"/>
    

    最终回到给浏览器跳转回Client1的响应。

    3、增加自定义realm

    创建类MyShiroRealm.java

    public class MyShiroRealm extends AuthorizingRealm { private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class); @Autowired private UserService userService; @Autowired private UserRoleService userRoleService; @Autowired private RoleService roleService; @Autowired private RolePermissionService rolePermissionService; @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取用户的输入的账号. String idObj =  token.getPrincipal(); Integer id = NumberUtils.toInt; User user = userService.findById; if (user == null) { // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址 return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getId(), user.getPwd(), getName; return authenticationInfo; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { /* * 当没有使用缓存的时候,不断刷新页面的话,这个代码会不断执行, * 当其实没有必要每次都重新设置权限信息,所以我们需要放到缓存中进行管理; * 当放到缓存中时,这样的话,doGetAuthorizationInfo就只会执行一次了, * 缓存过期之后会再次执行。 */ logger.debug("权限配置-->MyShiroRealm.doGetAuthorizationInfo; SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.addRole("ACTUATOR"); Integer userId = Integer.parseInt(principals.getPrimaryPrincipal().toString; //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 Set<Integer> roleIds = userRoleService.findRoleIds; Set<Role> roles = roleService.findByIds; for(Role role : roles){ authorizationInfo.addRole(role.getCode; } //设置权限信息. List<Permission> permissions = rolePermissionService.getPermissions; Set<String> set = new HashSet<String>(permissions.size; for(Permission permission : permissions){ if(StringUtils.isNotBlank(permission.getCode{ set.add(permission.getCode; } } authorizationInfo.setStringPermissions; return authorizationInfo; }}
    
    • doGetAuthenticationInfo用于申明用户账号音信,可依据现实事情来调动认证攻略
    • doGetAuthorizationInfo用于获取用户全体的剧中人物和权限

    4、成立登陆拦截器

    public class LoginFilter implements Filter { @Override public void destroy() {} @Override public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { Subject currentUser = SecurityUtils.getSubject(); if (!currentUser.isAuthenticated { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; AjaxResponseWriter.write(req, res, ServiceStatusEnum.UNLOGIN, "请登录"); return; } chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException {}}public class AjaxResponseWriter { /** * 写回数据到前端 * @param request * @param response * @param status {@link ServiceStatusEnum} * @param message 返回的描述信息 * @throws IOException */ public static void write(HttpServletRequest request,HttpServletResponse response,ServiceStatusEnum status,String message) throws IOException{ String contentType = "application/json"; response.setContentType(contentType); response.setCharacterEncoding; response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Origin",request.getHeader); Map<String, String> map = Maps.newLinkedHashMap(); map.put("code", status.code); map.put("msg", message); String result = JacksonHelper.toJson; PrintWriter out = response.getWriter(); try{ out.print; out.flush(); } finally { out.close(); } }}/** * 全局性状态码 * @author yangwk */public enum ServiceStatusEnum { UNLOGIN, //未登录 ILLEGAL_TOKEN,//非法的token ; public String code; private ServiceStatusEnum(String code){ this.code = code; }}
    
    • 用户登陆意况拦截器,不容许无名访谈的url会经过该filter,倘诺未登入,则赶回未登陆提醒(未登陆管理可依附实际工作开始展览调解)

    注意:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <version>1.5.2.RELEASE</version>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-data-redis</artifactId>
      <version>1.3.0.RELEASE</version>
    </dependency>
    
    4.1.1.2 访问接入Cas系统的施用系统Client2

    访问Client1并登入之后,访问Client2,与拜候Client1一模二样,先通过initialFlowSetupAction。
    继之登陆流程流转到第三个state(ticketGrantingTicketExistsCheck)。

    <action-state id="ticketGrantingTicketCheck">
            <evaluate expression="ticketGrantingTicketCheckAction"/>
            <transition on="notExists" to="gatewayRequestCheck"/>
            <transition on="invalid" to="terminateSession"/>
            <transition on="valid" to="hasServiceCheck"/>
        </action-state>
    

    因为已经登入过,具备诉求的Cookie中设有有效的TGT,于是流程跳转到hasServiceCheck。

     <decision-state id="hasServiceCheck">
            <if test="flowScope.service != null" then="renewRequestCheck" else="viewGenericLoginSuccess"/>
        </decision-state>
    

    看清是或不是是由运用页面跳转到登陆页面登录的,假若是,则跳转到generateServiceTicket,不是则跳转到viewGenericLoginSuccess。
    此地跳转到renewRequestCheck。

     <decision-state id="renewRequestCheck">
            <if test="requestParameters.renew != '' and requestParameters.renew != null" then="serviceAuthorizationCheck"
                else="generateServiceTicket"/>
        </decision-state>
    

    request中不设有renew,登陆流程流转到第八个state(generateServiceTicket)。

     <action-state id="generateServiceTicket">
            <evaluate expression="generateServiceTicketAction"/>
            <transition on="success" to="warn"/>
            <transition on="unregisteredService" to="viewGenericLoginSuccess"/>
            <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
            <transition on="error" to="initializeLogin"/>
            <transition on="gateway" to="gatewayServicesManagementCheck"/>
        </action-state>
    

    此伏彼起的流浪与运用种类webapp1同样,请参谋前面webapp1的漂流。

    5、添Garden录、退出职能

    @Api(value="用户登录",tags={"用户登录"})@RestControllerpublic class LoginController { private static Logger logger = LoggerFactory.getLogger(LoginController.class); @Value("${server.session.timeout}") private String serverSessionTimeout; /** * 用户登录接口 通过用户名和密码进行登录 */ @ApiOperation(value = "用户登录接口 通过用户名和密码进行登录", notes = "用户登录接口 通过用户名和密码进行登录") @ApiImplicitParams({ @ApiImplicitParam(paramType = "query", name = "username", value = "用户名", required = true, dataType = "String"), @ApiImplicitParam(paramType = "query", name = "pwd", value = "密码", required = true, dataType = "String"), @ApiImplicitParam(paramType = "query", name = "autoLogin", value = "自动登录", required = true, dataType = "boolean")}) @RequestMapping(value = "/login/submit",method={RequestMethod.GET,RequestMethod.POST}) public Map<String, String> subm(HttpServletRequest request,HttpServletResponse response, String username,String pwd,@RequestParam(value = "autoLogin", defaultValue = "false") boolean autoLogin) { Map<String, String> map = Maps.newLinkedHashMap(); Subject currentUser = SecurityUtils.getSubject(); User user = userService.findByUsername; if (user == null) { map.put("code", "-1"); map.put("description", "账号不存在"); return map; } if (user.getEnable { //账号被禁用 map.put("code", "-1"); map.put("description", "账号已被禁用"); return map; } String salt = user.getSalt(); UsernamePasswordToken token = null; Integer userId = user.getId(); token = new UsernamePasswordToken(userId.toString(),SaltMD5Util.encode(pwd, salt)); token.setRememberMe(autoLogin); loginValid(map, currentUser, token); // 验证是否登录成功 if (currentUser.isAuthenticated { map.put("code","1"); map.put("description", "ok"); map.put("id", String.valueOf; map.put("username", user.getUsername; map.put("name", user.getName; map.put("compnay_id", String.valueOf(user.getCompanyId; String uuidToken = UUID.randomUUID().toString(); map.put("token", uuidToken); currentUser.getSession().setTimeout(NumberUtils.toLong(serverSessionTimeout, 1800)*1000); request.getSession().setAttribute("token",uuidToken ); } else { map.put("code", "-1"); token.clear(); } return map; } @RequestMapping(value="logout",method=RequestMethod.GET) public Map<String, String> logout() { Map<String, String> map = Maps.newLinkedHashMap(); Subject currentUser = SecurityUtils.getSubject(); currentUser.logout(); map.put("code", "logout"); return map; } @RequestMapping(value="unauth",method=RequestMethod.GET) public Map<String, String> unauth() { Map<String, String> map = Maps.newLinkedHashMap(); map.put("code", "403"); map.put("msg", "你没有访问权限"); return map; } private boolean loginValid(Map<String, String> map,Subject currentUser, UsernamePasswordToken token) { String username = null; if (token != null) { username =  token.getPrincipal(); } try { // 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查 // 每个Realm都能在必要时对提交的AuthenticationTokens作出反应 // 所以这一步在调用login方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法 currentUser.login; return true; } catch (UnknownAccountException | IncorrectCredentialsException ex) { map.put("description", "账号或密码错误"); } catch (LockedAccountException lae) { map.put("description","账户已锁定"); } catch (ExcessiveAttemptsException eae) { map.put("description", "错误次数过多"); } catch (AuthenticationException ae) { // 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景 map.put("description", "登录失败"); logger.warn(String.format("对用户[%s]进行登录验证..验证未通过", username),ae); } return false; } @Autowired private UserService userService;}
    
    • 以上代码是比较通用的记名、退出职能,若无特殊需要,可平昔采纳上述功用

    输入 <tomcat_key> 的密钥口令

    3. 在application.properties中加多redis数据库的连带配置。这里为了演示使用形式只增多了针锋相投简便易行的安顿,即设置了session存款和储蓄的数据库类型、使用的数目库号、数据库地址和端口号。实战中还恐怕会对利用非暗中同意数据库、数据库大小、数据库最加纳阿克拉接数、生存时间长度、是不是写回磁盘等很多参数进行配备

    4.1.2 登出流程深入分析

    登出的流程定义在logout-webflow.xml中。
    率先会见登出接口/logout,流程跳转到terminateSession

     <action-state id="terminateSession">
        <evaluate expression="terminateSessionAction.terminate(flowRequestContext)" />
        <transition to="doLogout" />
      </action-state>
    

    登出的章程主要调用路线如下:

    TerminateSessionAction.terminate() 
    --> CentralAuthenticationServiceImpl.destroyTicketGrantingTicket()
    销毁TGT的方法
    --> LogoutManagerImpl.performLogout() 
    执行登出的方法,在该方法中向每个访问过的应用系统发送登出请求, 应用系统收到请求会销毁与用户的session
    --> handleLogoutForSloService()
    向应用系统发送登出请求的方法
    --> performBackChannelLogout()   发送登出请求
    

    terminateSessionAction.terminate()试行完结之后,流程跳转到do图标ut

     <action-state id="doLogout">
        <evaluate expression="logoutAction" />
        <transition on="finish" to="finishLogout" />
        <transition on="front" to="frontLogout" />
      </action-state>
    
     <decision-state id="finishLogout">
        <if test="flowScope.logoutRedirectUrl != null" then="redirectView" else="logoutView" />
      </decision-state>
    
      <end-state id="logoutView" view="externalRedirect:casLoginView" />
    

    谈到底跳转到登入页面。

    6、在接口上增添权限限制

    以UserController为例:

    @ApiOperation(value="获取用户详细信息", notes="根据ID查找用户")@ApiImplicitParam(paramType="query",name = "id", value = "用户ID", required = true,dataType="int")@RequiresPermissions(value={"user:get"}) @RequestMapping(value="/get",method=RequestMethod.GET)public User get{ User entity = userService.findById; entity.setPwd; entity.setSalt; return entity;}@ApiOperation(value="修改密码", notes="修改密码")@ApiImplicitParams({ @ApiImplicitParam(paramType = "query", name = "oldPwd", value = "旧密码", required = true, dataType = "String"), @ApiImplicitParam(paramType = "query", name = "pwd", value = "新密码", required = true, dataType = "String"), @ApiImplicitParam(paramType = "query", name = "confirmPwd", value = "新密码", required = true, dataType = "String")})@RequiresPermissions(value={"user:reset-pwd"})@RequestMapping(value="/reset-pwd",method=RequestMethod.POST)public Return resetPwd(String oldPwd,String pwd,String confirmPwd){ if(StringUtils.isBlank || StringUtils.isBlank || StringUtils.isBlank(confirmPwd) || !pwd.equals(confirmPwd)) { return Return.fail; } Subject currentUser = SecurityUtils.getSubject(); Integer userId= currentUser.getPrincipal(); User entity = userService.findById; if(!entity.getPwd().equals(SaltMD5Util.encode(oldPwd, entity.getSalt{ return Return.fail; } return userService.changePwd(entity,pwd);}
    
    • @RequiresPermissions 和 @RequiresRoles分别用于限制该方法可访谈的权位和剧中人物,两个假若还要选拔,默许是“&”关系;两个的value参数都足以设置为数组,数组成分间的涉嫌能够通过logical属性来安装,有Logical.AND,Logical.OMurano八个值可选择

    (假使和密钥库口令同样, 按回车) ,这里向来回车,也使用keystore密码changeit,不然tomcat运行报错!

    # Redis配置
    spring.session.store-type=redis
    spring.redis.database=0
    spring.redis.host=localhost
    spring.redis.port=6379
    

    4.2 Client端源码解析

    Cas client应用体系端通过多少个Filter来达成登入跳转和发表等作用。
    下边以在web.xml中安排的多少个Filter顺序来实行分析 。

    小结

    spring-boot整合shiro的步调如下:

    1. 添加maven依赖
    2. 增添ShiroConfigration配置,钦点shiro的为主配置
    3. 增多MyShiroRealm,钦命账户表明攻略和剧中人物权限获取格局
    4. 增加LoginFilter,即登入拦截器
    5. 添Garden录、退出职能
    6. 经过评释增添接口调用权限限制

    权力决定基于RBAC模型,涉及的表有:用户、角色、用户角色关系(user_role)、权限(permission)、剧中人物权限关系(role_permission),具体代码可参看github内的演示项目。

    自己搭建好的spring boot web后端开拓框架已上传至GitHub,招待嘲笑!

     

    4. 编辑一个测量检验的controller来证实是不是能够正确地读写session。这里的controller中,作者料定了当下拿走的session是还是不是是新生成的。假如是,则输出成功开创三个session对象,并赶回session的id,然后在session中增加三个字段。借使session不是新生成的,就是已经存在的session,则输出session是曾经存在的并赶回session的id,然后再出口session中初始创造session保存的key所对应的value

    4.2.1 SingleSignOutFilter

    org.jasig.cas.client.session.SingleSignOutFilter是处理登出恳求的Filter。该Filter判别是或不是是Cas Server端发过来的刊登需要,固然是发布要求,则基于央浼中的logoutMessage清除对应的Session。
    登出乞求的要紧调用路线如下:

    SingleSignOutFilter.doFilter()
    --> SingleSignOutHandler.process()
    --> destroySession(request)
    --> session.invalidate();
    

    2.配置ehcache缓存

    @SpringBootApplication
    @EnableRedisHttpSession
    @RestController
    public class DemoApplication {
    
      private Logger logger = LoggerFactory.getLogger(this.getClass());
    
      public static void main(String[] args) {
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.setWebEnvironment(true);
        app.run(args);
      }
    
      @GetMapping("/hello")
      public ResponseEntity<?> hello(HttpSession session) {
        if (session.isNew()) {
          logger.info("Successfully creates a session ,the id of session :"   session.getId());
          session.setAttribute("key", "hello");
        } else {
          logger.info("session already exists in the server, the id of session :"  session.getId());
          logger.info(session.getAttribute("key").toString());
        }
        return new ResponseEntity<>("Hello World", HttpStatus.OK);
      }
    
    }
    
    4.2.2 AuthenticationFilter

    org.jasig.cas.client.authentication.AuthenticationFilter是认证必要是还是不是登录过的Filter。

    public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            // 判断该请求是否不需要验证,如果不需要,则跳转到下一个Filter
    if(this.isRequestUrlExcluded(request)) {
                this.logger.debug("Request is ignored.");
                filterChain.doFilter(request, response);
            } else {
                HttpSession session = request.getSession(false);
               //从session中获取名为"_const_cas_assertion_"的Assertion 
     Assertion assertion = session != null?(Assertion)session.getAttribute("_const_cas_assertion_"):null;
               //如果存在,则说明已经登录,本过滤器处理完成,处理下个过滤器 
              if(assertion != null) {
                    filterChain.doFilter(request, response);
                } else {
    //生成serviceUrl  
                    String serviceUrl = this.constructServiceUrl(request, response);
    //从request中获取ST 
                    String ticket = this.retrieveTicketFromRequest(request);
                    boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
                    //如果ticket不为空,本过滤器处理完成,处理下个过滤器 
    if(!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
                        this.logger.debug("no ticket and no assertion found");
                        String modifiedServiceUrl;
                        if(this.gateway) {
                            this.logger.debug("setting gateway attribute in session");
                            modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
                        } else {
                            modifiedServiceUrl = serviceUrl;
                        }
    
                        this.logger.debug("Constructed service url: {}", modifiedServiceUrl);
                      //生成重定向URL 
                        String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
                        this.logger.debug("redirecting to "{}"", urlToRedirectTo);
                        String reqType = request.getHeader("X-Requested-With");
                        //如果是异步请求,则返回410状态码给前端
                        if("XMLHttpRequest".equalsIgnoreCase(reqType)) {
                            String json = "{"flag":0,"error":401,"data":{}}";
                            response.getWriter().write(json);
                        } else {
                        //跳转到CAS服务器的登录页面 
                            this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
                        }
    
                    } else {
                        filterChain.doFilter(request, response);
                    }
                }
            }
        }
    

    当我们从浏览器访谈安插了单点登陆的运用种类时(http://www.client1.com/index),由于集成了CAS单点登陆客户端,此时跻身到第2个过滤器AuthenticationFilter(不怀念任何非单点登陆的过滤器),试行以下操作:
    1 从session中拿走名称叫“const_cas_assertion”的assertion对象,剖断assertion是还是不是留存,假使存在,表达已经报到,实行下贰个过滤器。借使空中楼阁,推行第2步。
    2 生成serviceUrl(http://www.client1.com/index),从request中获得票据参数ticket,剖断ticket是还是不是为空,假使不为空试行下三个过滤器。倘诺为空,实践第3步。
    3 生成重定向UPRADOL,如:
    http://www.casserver.com/login?service=http://www.client1.com/index
    4 跳转到单点登陆服务器,展现登入页面,此时第二个过滤器实施到位。

    本文由1010cc时时彩经典版发布于1010cc时时彩经典版,转载请注明出处:【1010cc时时彩经典版】Boot项目利用Redis实现sess

    关键词:

上一篇:没有了

下一篇:没有了