2019-11-02 21:22  阅读(1172)
文章分类:Spring Security 源码分析 文章标签:Spring SecuritySpring Security 源码
©  原文作者: 郑龙飞 原文地址:https://juejin.cn/user/4212984285237870

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

前言

本章是根据前面Spring Security系列实现一个基于角色的权限管理系统。

技术栈

  • Spring Boot
  • Spring Security
  • Spring Social(需配置host127.0.0.1 www.merryyou.cn
  • Spring Data JPA
  • Freemarker
  • Mysql
  • Redis
  • 前端miniui(非开源)

效果图

202105291544467601.png
202105291544521662.png
202105291544561953.png
202105291544563194.png
202105291544564415.png
202105291544565356.png
202105291544565937.png
202105291544566788.png
202105291544567849.png
2021052915445689410.png

部分代码

    $.ajax({
                url: "${re.contextPath}/connect",
                type: "get",
                async: true,
                dataType: "json",
                success: function (data) {
                    if (data.code === 0) {
                        if (data.data.qq) {
                            //解绑
                            $("#bindingQq").attr("title", "解绑")
                            $(".fa-qq").addClass("social_title");
                        } else {
                            //绑定
                            $("#bindingQq").attr("title", "绑定")
                            $(".fa-qq").removeClass("social_title");
                        }
                        if (data.data.weixin) {
                            //解绑
                            $("#bindingWeixin").attr("title", "解绑")
                            $(".fa-weixin").addClass("social_title");
                        } else {
                            //绑定
                            $("#bindingWeixin").attr("title", "绑定")
                            $(".fa-weixin").removeClass("social_title");
                        }
                        if (data.data.weibo) {
                            //解绑
                            $("#bindingWeibo").attr("title", "解绑")
                            $(".fa-weibo").addClass("social_title");
                        } else {
                            //绑定
                            $("#bindingWeibo").attr("title", "绑定")
                            $(".fa-weibo").removeClass("social_title");
                        }
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(XMLHttpRequest.status);
                    alert(XMLHttpRequest.readyState);
                    alert(textStatus); // paser error;
                }
    
            });
    复制代码
    $.ajax({
                    url: "${re.contextPath}/role/" + data.id,
                    cache: false,
                    success: function (text) {
                        var o = mini.decode(text);
                        //设置数的选中状态
                        console.log(o.menuIds);
                        var nodes = tree.getAllChildNodes(tree.getRootNode());
                        for(var i=0;i<nodes.length;i++){
                            if(o.menuIds.indexOf(nodes[i]['id'])>=0){
                                tree.checkNode(nodes[i]);
                            }else{
                                tree.uncheckNode(nodes[i]);
                            }
                        }
                        form.setData(o);
                        form.setChanged(false);
                    }
                });
    复制代码
        @Override
        public List<MenuDto> getMenusList() {
            return repository.findAll().stream()
                    .map(e ->new MenuDto(e.getId(), e.getPId(), e.getName(), e.getUrl()))
                    .collect(Collectors.toList());
        }
    
        @Override
        public Set<String> getUrlByname(String username) {
            Set<SysMenu> mesnus = new HashSet<>();
            userRepository.findByUsername(username)
                    .getRoles()
                    .forEach(e->mesnus.addAll(e.getMenus()));
            return mesnus.stream().map(e->e.getUrl()).collect(Collectors.toSet());
        }
    复制代码
    protected void configure(HttpSecurity http) throws Exception {
    //        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
            http.headers().frameOptions().disable().and()
                    .formLogin()//使用表单登录,不再使用默认httpBasic方式
                    .loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL)//如果请求的URL需要认证则跳转的URL
                    .loginProcessingUrl(SecurityConstants.DEFAULT_SIGN_IN_PROCESSING_URL_FORM)//处理表单中自定义的登录URL
                    .successHandler(merryyouLoginSuccessHandler)//登录成功处理器,返回JSON
                    .failureHandler(merryyouAuthenticationfailureHandler)//登录失败处理器
                    .and()
                    .apply(validateCodeSecurityConfig)//验证码拦截
                    .and()
                    .apply(smsCodeAuthenticationSecurityConfig)
                    .and()
                    .apply(merryyouSpringSocialConfigurer)//社交登录
                    .and()
                    .rememberMe()
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(securityProperties.getRememberMeSeconds())
                    .userDetailsService(userDetailsService)
                    .and()
                    .sessionManagement()
    //                .invalidSessionStrategy(invalidSessionStrategy)
                    .invalidSessionUrl("/session/invalid")
                    .maximumSessions(securityProperties.getSession().getMaximumSessions())//最大session并发数量1
                    .maxSessionsPreventsLogin(securityProperties.getSession().isMaxSessionsPreventsLogin())//之后的登录踢掉之前的登录
                    .expiredSessionStrategy(sessionInformationExpiredStrategy)
                    .and()
                    .and()
                    .logout()
                    .logoutUrl("/signOut")//默认退出地址/logout
                    .logoutSuccessUrl("/")//退出之后跳转到注册页面
                    .deleteCookies("JSESSIONID")
                    .and()
                    .authorizeRequests().antMatchers(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
                    SecurityConstants.DEFAULT_SIGN_IN_PROCESSING_URL_FORM,
                    SecurityConstants.DEFAULT_REGISTER_URL,
                    SecurityConstants.DEFAULT_SIGN_IN_PROCESSING_URL_MOBILE,
                    SecurityConstants.DEFAULT_SIGN_IN_URL_MOBILE_PAGE,
                    "/register",
                    "/socialRegister",//社交账号注册和绑定页面
                    "/user/register",//处理社交注册请求
                    "/social/info",//获取当前社交用户信息
                    "/session/invalid",
                    "/**/*.js",
                    "/**/*.css",
                    "/**/*.jpg",
                    "/**/*.png",
                    "/**/*.woff2",
                    "/code/*")
                    .permitAll()//以上的请求都不需要认证
                    //.antMatchers("/").access("hasRole('USER')")
                    .and()
                    .csrf().disable()//关闭csrd拦截
            ;
            //安全模块单独配置
            authorizeConfigProvider.config(http.authorizeRequests());
        }
    复制代码
    @PreAuthorize("hasAnyAuthority('user:select','user:update')")
        @PostMapping(value = "/user/saveUser")
        @ResponseBody
        public Result saveUser(@RequestParam String data) {
            log.info(data);
            return sysUserService.save(data);
        }
    复制代码
    <td style="width:100%;">
                         <@sec.authorize access="hasAuthority('role:add')">
                        <a class="mini-button" iconCls="icon-add" onclick="add()">增加</a>
                         </@sec.authorize>
                         <@sec.authorize access="hasAuthority('role:update')">
                        <a class="mini-button" iconCls="icon-add" onclick="edit()">编辑</a>
                         <@sec.authorize access="hasAuthority('role:del')">
                          </@sec.authorize>
                        <a class="mini-button" iconCls="icon-remove" onclick="remove()">删除</a>
                         </@sec.authorize>
                    </td>
    复制代码

启动方式

  1. idea 配置lombok插件,参考lombok-intellij-plugin
  2. 修改application.yml中数据源信息,执行db文件夹下面的sql文件
  3. 修改application-dev.yml 中redis连接信息
  4. 社交登录需配置host文件:127.0.0.1 www.merryyou.cn 微信appid已过期

代码下载

推荐文章

  1. 【译】用Java创建你的第一个区块链-part1
  2. 【译】用Java创建你的第一个区块链-part2:可交易

2021052915445701511.png

关注微信小程序java架构师历程
上下班的路上无聊吗?还在看小说、新闻吗?不知道怎样提高自己的技术吗?来吧这里有你需要的java架构文章,1.5w+的java工程师都在看,你还在等什么?

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Spring Security源码分析十六:Spring Security项目实战
上一篇
Spring Security源码分析十五:Spring Security 页面权限控制