Spring Security 源码分析十六:Spring Security 项目实战

1. 前言

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

1.1 技术栈

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

1.2 效果图https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_03.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_04.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_05.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_06.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_07.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_08.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_09.pnghttps://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/logback/logback_10.png

1.3 部分代码

$.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.4 启动方式

  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已过期

2. 代码下载

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值