美文网首页
Spring Boot整合Spring Security

Spring Boot整合Spring Security

作者: MaLizhi | 来源:发表于2018-12-19 00:58 被阅读48次

    前言:安全框架目前有两大主流,一个是apache的Shiro,一个是Spring的Security,曾经用过Shiro,又想看一下security和Shiro的不同,又加上Spring Boot可以无缝对接Security,所以在此使用Security作为安全组件。
    安全框架主要功能为:身份认证,权限控制,预防漏洞攻击
    所以接下来我们围绕如果配置身份认证,权限控制去整合Security。

    环境: IDEA版本2017.3.1 x64, JDK1.8, SpringBoot2.1.1, Druid1.1.8, mybatis1.3.2,Security5.1.2,thymeleaf3.0.11

    总流程:

    • 引入security的依赖包以及和security-thymeleaf的整合包
    • 实现MySecurityConfig配置类去定制我们的授权规则和认证策略
    • 实现UserDetailsService认证策略用于MySecurityConfig类
    • 编写一个Controller用于测试权限
    • 前端页面限制角色访问内容
    • 数据库需要注意的问题

    一、引入security的依赖包以及和security-thymeleaf的整合包

            <!--引入security-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    
            <!-- 引入security与thymeleaf的整合依赖 -->
            <dependency>
                <groupId>org.thymeleaf.extras</groupId>
                <artifactId>thymeleaf-extras-springsecurity5</artifactId>
                <version>3.0.4.RELEASE</version>
            </dependency>
    

    二、实现MySecurityConfig配置类去定制我们的授权规则和认证策略

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        MyUserDetailsService myUserDetailsService;
    
        //定制请求的授权规则
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers("/").permitAll()
                    .antMatchers("/level1/**").hasRole("VIP1")
                    .antMatchers("/level2/**").hasRole("VIP2")
                    .antMatchers("/level3/**").hasRole("VIP3");
            
            /*开启自动配置的登录功能,如果是自己的定制的登入页面,那么/userlogin 的get请求是来到登录页面,/userlogin的post请求是处理认证登录
            也就是loginPage中的URL的post请求是处理登录逻辑的。没登录的时候,访问会以get的方式访问loginpage的URL来到登录页面*/
            http.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/userlogin");
            
            //开启自动配置的注销功能,会访问/logout请求
            http.logout().logoutSuccessUrl("/"); //注销成功后,回到首页
            
            /*开启记住我功能(开启后,springboot会给浏览器发送一个cookies,以后访问网站都会带上这个cookies给springboot验证,springboot会检查以前某一个用户的cookies的值是什么,如果找到了,这个用户就不用再次登录了,注销时候springboot会发送命令给浏览器删除cookies)*/
            http.rememberMe();
        }
    
        //定义认证规则
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
           //使用自定义认证规则,并且使用BCrypt算法处理密码
           auth.userDetailsService(myUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
        }
    }
    

    主要就是配置授权规则和认证策略,认证策略我们是连数据库去校验我们的用户和密码,所以需要去实现一个UserDetailsService。

    三、实现UserDetailsService认证策略用于MySecurityConfig

    @Service
    public class MyUserDetailsService implements UserDetailsService{
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        UserService userService;
        @Autowired
        HttpServletRequest request;
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User user = userService.selectUser(username);
            //logger.info(user.getName());
            if (user == null){
                throw new UsernameNotFoundException("用户名不存在!");
            }
            HttpSession session = request.getSession();
            session.setAttribute("user",user);
            session.setAttribute("sessusername",username);
    
            List<GrantedAuthority> authorities = new ArrayList<>();
    
            //角色
            authorities.add(new SimpleGrantedAuthority(user.getRole()));
    
            //权限(为了测试,硬编码,实际上应该从数据库中读取)
            authorities.add(new SimpleGrantedAuthority("1"));
    
            logger.info(user.getName()+"角色权限为:"+authorities.toString());
    
            return new org.springframework.security.core.userdetails.User(user.getName(),user.getPassword(),authorities);
        }
    }
    

    四、编写一个Controller用于测试权限

    @Controller
    public class KungfuController {
        private final String PREFIX = "pages/";
        /**
         * 欢迎页
         * @return
         */
        @GetMapping("/")
        public String index() {
            return "welcome";
        }
        
        /**
         * 登陆页
         * @return
         */
        @GetMapping("/userlogin")
        public String loginPage() {
            return PREFIX+"login";
        }
        
        /**
         * level1页面映射
         * @param path
         * @return
         */
    
        //@PreAuthorize("hasRole('VIP1') AND hasAuthority('1')")
        @PreAuthorize("hasAuthority('1')")
        @GetMapping("/level1/{path}")
        public String level1(@PathVariable("path")String path) {
            return PREFIX+"level1/"+path;
        }
    
    }
    

    后台的内容就实现了,接下来看前端如何限制角色访问内容

    五、前端页面限制角色访问内容

    登录页核心内容:

    页面需导入security和thymeleaf的整合标签
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"

    div align="center">
            <form th:action="@{/userlogin}" method="post">
                用户名:<input name="username"/><br>
                密码:<input name="password"><br/>
                <p>
                    <label for="remember-me">Remember Me?</label>
                    <input type="checkbox" id="remember-me" name="remember-me"/>
                </p>
                <input type="submit" value="登陆">
            </form>
        </div>
    
    主页核心内容:
    <div sec:authorize="!isAuthenticated()">
        <h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/userlogin}">请登录</a></h2>
    </div>
    <div sec:authorize="isAuthenticated()">
        <h2><span sec:authentication="name"></span>你好,你的角色为:
            <span sec:authentication="principal.authorities"></span>
        </h2>
        <form th:action="@{/logout}" th:method="post">
            <input th:type="submit" th:value="注销"/>
        </form>
    </div>
    <hr>
    
    <div sec:authorize="hasRole('VIP1')">
        <h3>普通武功秘籍</h3>
        <ul>
            <li><a th:href="@{/level1/1}">罗汉拳</a></li>
            <li><a th:href="@{/level1/2}">武当长拳</a></li>
            <li><a th:href="@{/level1/3}">全真剑法</a></li>
        </ul>
    </div>
    

    六、数据库实现

    为了测试,数据库设计过于简陋,但注意的问题为角色字段的内容需要加上ROLE_前缀,否则会security会认为此用户依然没有权限

    image

    密码可以编写一个工具类进行加密
    工具类如下:

    @Component
    public class BCryptUtil {
    
        private BCryptPasswordEncoder bCryptPasswordEncoder;
    
        public BCryptUtil(){
             this.bCryptPasswordEncoder =  new BCryptPasswordEncoder();
        }
    
        /**
         * 加密
         * @return
         */
        public String encoder(String password){
            return bCryptPasswordEncoder.encode(password);
        }
    
        /**
         * 验证密码
         * @param password
         * @param salt
         * @return
         */
        public Boolean matches(String password,String salt){
            return  bCryptPasswordEncoder.matches(password,salt);
        }
    
    }
    

    整合就到此完毕,时间较晚,如果有错漏尽管提出。

    更多Spring Boot整合可浏览此博客:malizhi.cn

    相关文章

      网友评论

          本文标题:Spring Boot整合Spring Security

          本文链接:https://www.haomeiwen.com/subject/zcfdkqtx.html