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;
}
}
遇到得问题:
- 页面嵌套时出现问题 解决:http.headers().frameOptions().sameOrigin(); 配置同源跨域得配置;
- 安全拦截机制得书写;
http.authorizeRequests() .antMatchers("放行路径").permitAll() //放行路径后加.permitAll() .antMatchers("需要授权得请求").hasAuthority("权限") //请求需要对应得权限 .anyRequest() //除放行请求外所有请求都需要验证 .authenticated() //开启验证 - 配置放行静态资源失败,直接添加"/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());
}