spring boot 项目集成security

springboot集成security需要三步:

一、引入依赖

         <!--集成安全框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
        </dependency>
        <!--thymeleaf整合security:依赖,旧版springboot不支持5版本,使用4版本集成安全框架-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

二、WebSecurityConfigurerAdapter抽象类得子类实现

 具体实现类

package com.offcn.pj.controller.page.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @Author 22768
 * @Date 2022/4/18 14:56
 * @Function
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /*安全拦截机制*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/tologin").permitAll()  //放行登录方法
                .antMatchers("/**").hasAuthority("admin")    //其余所有请求需要admin得权限
                .anyRequest() //其余所有请求
                .authenticated() //开启验证
                ;
        /*没有权限进入登录界面  默认跳转地址:/login Security默认页面*/
        http.formLogin()
                .loginPage("/tologin")   //自定义登陆页面  因为引入了thymeleaf  因此我设置得是controller层跳转登陆页面的接口
                .loginProcessingUrl("/dologin")    //这是登录页面得表单上的方法
                .usernameParameter("name")   //绑定表单上的name作为username   也即是用户名
                .passwordParameter("pwd")    //绑定表单上得pwd 作为password  也就是密码
                .successForwardUrl("/login") //成功登录
        ;

        http.csrf()
                .disable();//关闭 csrf 防护

        http
                .headers()
                .frameOptions()
                .sameOrigin(); //  因为用了页面嵌套  所以需要 配置   // 同源跨域,默认DENY
    }

    //注入UserDetailsService接口得实现类,自定义得类
    @Autowired
    protected  UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常情况下应该从数据库中读 配置认证需要的userservice  与 密码加/解密类
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    /*
    * 忽略静态文件得访问控制
    * 放行静态资源
    * */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //配置静态文件不需要认证
        web.ignoring().antMatchers("/css/**" ,"/js/**" ,"/plugins/**" ,"/fonts/**" ,"/images/**" , "/img/**" ,"**/favicon.ico","/indexIn.html" );
    }
}

login.htm页面对应设置

自定义登陆页面得接口跳转方法

 三、UserDetailsService得实现类得书写  ,因为我用了数据库中的数据做的验证,不是内存形式得,因此需要实现UserDetailsService接口

package com.offcn.pj.bean.security.impl;

import com.offcn.pj.dao.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;

/**
 * @Author 22768
 * @Date 2022/4/19 10:07
 * @Function
 */
@RestController
public class UserDetailsServiceImpl implements UserDetailsService {
    
    /*注入userMapper*/
    @Autowired
    private UserMapper usermapper;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        ArrayList<GrantedAuthority>  grantedAuthorities= new ArrayList<>();
        //授权是写死得   没用使用数据库  与用户使用数据库得配置相似  先做的用户的数据库配置
        grantedAuthorities.add(new SimpleGrantedAuthority("admin"));
        //因为我得user与安全框架中的user重名,因此需要全类限定名去标识,
        //  获取数据库中的user数据   
        com.offcn.pj.bean.User tbuser = usermapper.selectByPrimaryKey(username);
        if(tbuser == null){
            // 登录失败
            return null;
        }
        /*因为我得数据库中的密码是未加密得
        * 测试需要就在这一步人为加密,需要与SecurityConfig.java  文件中配置的解密类保持一致
        * */
        String pwd = tbuser.getPwd();
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        tbuser.setPwd(encoder.encode(pwd));
        // 审核通过
        if(tbuser.getFlag().equals("1")){
            return null;
        }
//        Role role = new Role();
//        role.setRflag(tbuser.getFlag());
//        List<Role> roleList = roleService.findRoleList(role);
//        Map<String,Object> map=new HashMap<>();
//        map.put("username",tbuser.getName());
//        map.put("id",tbuser.getId());
//        map.put("role", roleList);
//        String s = JSON.toJSONString(map);
        //返回得user是security得内部得user  因此注释解释方便区分
        User user = new User(tbuser.getId(), tbuser.getPwd(),grantedAuthorities);
        return user;
    }

}

 遇到得问题:

  1. 页面嵌套时出现问题   解决:http.headers().frameOptions().sameOrigin();  配置同源跨域得配置;
  2. 安全拦截机制得书写;
       http.authorizeRequests()
                    .antMatchers("放行路径").permitAll()  //放行路径后加.permitAll()
                    .antMatchers("需要授权得请求").hasAuthority("权限")  //请求需要对应得权限
                    .anyRequest() //除放行请求外所有请求都需要验证
                    .authenticated() //开启验证
  3.  配置放行静态资源失败,直接添加"/static/**"的话我这里没有生效,因为上面有静态资源目录的默认配置,请求到拦截器这里的时候 springboot还没有将/static/加载到路径上去,没有加载拦截器识别不到,所以没有生效依然访问不到静态资源;正确示例如下:
 /*
    * 忽略静态文件得访问控制
    * 放行静态资源
    * */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //配置静态文件不需要认证
        web.ignoring().antMatchers("/css/**" ,"/js/**" ,"/plugins/**" ,"/fonts/**" ,"/images/**" , "/img/**" ,"**/favicon.ico","/indexIn.html" );
    }

        4.java.lang.StackOverflowError: null(栈溢出异常),注入uerDetailservice时出现了这个异常,是因为 注入方式问题  我用的  new  得方式  实际用法如下:

//注入UserDetailsService接口得实现类,自定义得类
    @Autowired
    protected  UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常情况下应该从数据库中读 配置认证需要的userservice  与 密码加/解密类
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }