spingsecurity使用和说明
1、引入spingsecurity依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
启动项目访问 http://localhost:8080/login 账号:user 密码:控制台系统生成的
2、配置自定义用户名密码
配置文件配置
# 应用服务 WEB 访问端口
server.port=8080
spring.security.user.name=admin
spring.security.user.password=123456
或者 方法中配置(优先级高)
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// 这种方式认证用户名和密码比配置容器中 UserDetailsService方法级别高
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().
withUser("root"). // 用户名
password(this.passwordEncoder().encode("123")) 密码
.roles("admin"); //角色
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3、获取当前登录用户信息
package com.example.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
public class CurrentLoginUserInfoController {
/**
* 从当前请求对象中获取
*/
@GetMapping("/getLoginUserInfo")
public Principal getLoginUserInfo(Principal principle){
return principle;
}
/**
*从当前请求对象中获取
*/
@GetMapping("/getLoginUserInfo1")
public Authentication getLoginUserInfo1(Authentication authentication){
return authentication;
}
/**
* 从SecurityContextHolder获取
* @return
*/
@GetMapping("/getLoginUserInfo2")
public Authentication getLoginUserInfo(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication;
}
}
4、授权(对URL进行授权)
实现了认证功能,但是受保护的资源是默认的,默认所有认证(登录)用户均可以访问所有资源,不能根据实际情况进行角色管理,要实现授权功能,需重写WebSecurityConfigureAdapter 中的一个configure方法
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//角色student或者teacher都可以访问/student/** 这样的url
.mvcMatchers("/student/*").hasAnyRole("student", "teacher")
// 角色teacher 可以访问teacher/**
.mvcMatchers("/teacher/**").hasRole("teacher")
//权限admin:query 可以访问/admin**
// .mvcMatchers("/admin/**").hasAuthority("admin:query")
//角色teacher 或者权限admin:query 觉可以访问admin/**
.mvcMatchers("/admin/**").access("hasRole('teacher') or hasAuthority('admin:query')")
//任何请求均需要认证
.anyRequest().authenticated();
//使用表单登录
http.formLogin();
}
}
5、授权(方法级别的权限控制)
我们可以通过注解灵活的配置方法安全,我们先通过@EnableGlobalMethodSecurity开启基于注解的安全配置。
WebSecurityConfig方法
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启全局方法安全,启用预授权注解和后授权注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//controller 的权限配置,可以在这里配置
http.authorizeRequests().anyRequest().authenticated();//任何请求均需要认证
http.formLogin().permitAll(); //放开登录页面及登录接口
}
}
MySecurityUserConfig方法
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@Slf4j
public class MySecurityUserConfig {
@Bean
public UserDetailsService userDetailsService(){
//新建用户
UserDetails user1= User.builder()
.username("eric")
.password(passwordEncoder().encode("123456")) //用户密码必须加密
.roles("student") //角色 转变成权限(ROLE_student)
.build();
UserDetails user2= User.builder()
.username("thomas")
.password(passwordEncoder().encode("123456")) //用户密码必须加密
.authorities("teacher:query")
.build();
UserDetails user3= User.builder()
.username("admin")
.password(passwordEncoder().encode("123456")) //用户密码必须加密
.authorities("teacher:query","teacher:add","teacher:update","teacher:delete")
.build();
InMemoryUserDetailsManager userDetailsService =new InMemoryUserDetailsManager();
userDetailsService.createUser(user1);
userDetailsService.createUser(user2);
userDetailsService.createUser(user3);
return userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
TeacherService业务接口
package com.example.service;
public interface TeacherService {
String add();
String update();
String delete();
String query();
}
TeacherServiceImpl业务接口实现类
package com.example.service.impl;
import com.powernode.service.TeacherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class TeacherServiceImpl implements TeacherService {
@Override
@PreAuthorize("hasAuthority('teacher:add')") //预授权
public String add() {
log.info("添加教师成功");
return "添加教师成功";
}
@Override
@PreAuthorize("hasAnyAuthority('teacher:update')") //预授权
public String update() {
log.info("修改教师成功");
return "修改教师成功";
}
@Override
@PreAuthorize("hasAuthority('teacher:delete')") //预授权
public String delete() {
log.info("删除教师成功");
return "删除教师成功";
}
@Override
@PreAuthorize("hasAnyAuthority('teacher:query')") //预授权
public String query() {
log.info("查询教师成功");
return "查询教师成功";
}
}
TeacherController控制类
package com.example.controller;
import com.powernode.service.TeacherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/teacher")
@Slf4j
public class TeacherController {
@Resource
private TeacherService teacherService;
@GetMapping("/query")
public String queryInfo() {
return teacherService.query();
}
@GetMapping("/add")
public String addInfo() {
return teacherService.add();
}
@GetMapping("/update")
public String updateInfo() {
int a=10;
log.info("进入更新教师controller");
return teacherService.update();
}
@GetMapping("/delete")
public String deleteInfo() {
return teacherService.delete();
}
}
6、认证返回json统一返回数据格式
统一消息格式对象类 HttpResult
package com.example.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor //用于生成类的构造函数。
@NoArgsConstructor //用于生成无参构造函数
@Builder //生成建造者模式
public class HttpResult {
private Integer code; //返回给前端的自定义响应码
private String msg; // 返回给前端的消息
private Object data; //返回给前端的数据
}
在配置包里新建4个配置类
AppAutheticationSuccessHandler //配置认证成功处理器
AppAuthenticationFailHandler //配置认证失败处理器
AppLogoutSuccessHanlder //配置退出成功处理器
AppAccessDenyHanlder //配置访问拒绝处理器
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 认证成功就会调用该接口里的方法
*/
@Component
@Slf4j
public class AppAutheticationSuccessHandler implements AuthenticationSuccessHandler {
@Resource
private ObjectMapper objectMapper; //可以进行序列化(json)和反序列化,
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HttpResult httpResult=HttpResult.builder()
.code(1)
.msg("登录成功")
.build();
String responseJson = objectMapper.writeValueAsString(httpResult);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(responseJson);
writer.flush();
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
@Slf4j
public class AppAuthenticationFailHandler implements AuthenticationFailureHandler {
@Resource
private ObjectMapper objectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
HttpResult httpResult=HttpResult.builder()
.code(0)
.msg("登录失败")
.build();
String responseJson = objectMapper.writeValueAsString(httpResult);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(responseJson);
writer.flush();
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
@Slf4j
public class AppLogoutSuccessHanlder implements LogoutSuccessHandler {
@Resource
private ObjectMapper objectMapper;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HttpResult httpResult=HttpResult.builder()
.code(1)
.msg("退出成功")
.build();
String responseJson = objectMapper.writeValueAsString(httpResult);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(responseJson);
writer.flush();
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
@Slf4j
public class AppAccessDenyHanlder implements AccessDeniedHandler {
@Resource
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
HttpResult httpResult=HttpResult.builder()
.code(0)
.msg("您没有权限访问该资源!!")
.build();
String responseJson = objectMapper.writeValueAsString(httpResult);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(responseJson);
writer.flush();
}
}
认证用户类 UserDetailsService ,修改容器中认证用户类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* 定义一个bean,用户详情服务接口
*/
@Configuration
public class MySecurityUserConfig {
@Bean
public UserDetailsService userDetailsService(){
//创建了2个用户,系统的用户
UserDetails user1= User.builder()
.username("eric")
.password(passwordEncoder().encode("123456"))
.roles("student") //角色的前面加上ROLE_student 就变成了权限
.build();
UserDetails user2= User.builder()
.username("thomas")
.password(passwordEncoder().encode("123456"))
.roles("teacher") //ROLE_teacher
.build();
InMemoryUserDetailsManager userDetailsService=new InMemoryUserDetailsManager();
userDetailsService.createUser(user1);
userDetailsService.createUser(user2);
return userDetailsService;
}
/**
* 自定义用户必须配置密码编码器
* @return
*/
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
在WebSecurityConfig中配置各种情况的处理器
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.annotation.Resource;
@Configuration
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private AppAutheticationSuccessHandler appAutheticationSuccessHandler;
@Resource
private AppAuthenticationFailHandler appAuthenticationFailHandler;
@Resource
private AppLogoutSuccessHanlder appLogoutSuccessHanlder;
@Resource
private AppAccessDenyHanlder appAccessDenyHanlder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/student/**")
.hasRole("student")
.anyRequest().authenticated();
//设置登录成功的处理器
http.formLogin()
.successHandler(appAutheticationSuccessHandler) //配置认证成功处理器
.failureHandler(appAuthenticationFailHandler) //配置认证失败处理器
.permitAll();
http.logout().logoutSuccessHandler(appLogoutSuccessHanlder);//配置退出成功处理器
//配置访问拒绝处理器
http.exceptionHandling().accessDeniedHandler(appAccessDenyHanlder);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人