SpringSecurity
springsecurity只需要添加一个依赖就可以保护所有的接口。
手动配置用户名和密码
- 配置文件中配置
spring.security.user.name=admin
spring.security.user.password=123456
spring.security.user.roles=admin
注释要另起一行;配置项目后面不要有空格。
- Java代码中配置
新建一个config包,创建SecurityConfig类,继承WebSecurityConfigurerAdapter,重写configure方法。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("123").roles("admin")
.and()
.withUser("hurui").password("456").roles("user");
}
这个方法从springboot5以后就不行了,因为密码要加密。在代码之前添加一个passwordEncoder()方法。
要用Bean注入
@Bean
PasswordEncoder passwordEncoder(){
// 已经不用了
return NoOpPasswordEncoder.getInstance();
}
SpringSecurity中httpSecurity配置
作用:配置拦截规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 开启配置
.antMatchers("/admin/**") // 选择路径规则 => /admin/** 只有admin能访问
.hasRole("admin") // 需要的角色
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated() // 剩下的路径,登录之后才能访问
.and()
.formLogin() // 登录信息
.loginProcessingUrl("/doLogin") // 处理登录请求的地址
.loginPage("/login") // 登录页面 => 前后端分离不配
.usernameParameter("user") // 将请求字段中默认的username改为user,名字上的区别
// ?username='***' => ?user='***'
.passwordParameter("pwd")
// successHandler登录成功返回的信息,一般用在前后端分离的项目,返回一个json
// successForwardUrl()登录成功后跳转的url,
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
Authentication authentication) throws IOException, ServletException {
// authentication保存了登录成功的信息
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("status",200);
map.put("msg",authentication.getPrincipal());
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
AuthenticationException e) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("status",500);
if (e instanceof LockedException) {
map.put("msg","账户被锁定,登录失败");
} else if (e instanceof BadCredentialsException){
map.put("msg","账户密码错误!");
} else if (e instanceof DisabledException) {
map.put("msg","账户被禁用!");
} else if (e instanceof AccountExpiredException) {
map.put("msg","账户过期!");
} else if (e instanceof CredentialsExpiredException) {
map.put("msg","密码过期!");
} else {
map.put("msg","登录失败!");
}
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll() // 和登录相关的可以直接访问
.and()
.csrf().disable(); // 关闭csrf
}
多个HttpSecurity配置
@Configuration
public class MultiHttpSecurityConfig {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("111").roles("admin")
.and()
.withUser("hurui").password("222").roles("user");
}
// 静态内部类配置不同的securityConfig类,Order配置优先级
@Configuration
@Order(1)
public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/admin/**").authorizeRequests().anyRequest().hasRole("admin");
}
}
@Configuration
public static class OtherSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")
.permitAll()
.and()
.csrf()
.disable();
}
}
}
密码加密
Spring boot自带了一个密码加密方法:BCryptPasswordEncode(),在之前的加密方法中return 这个方法就可以了。
方法安全
在方法上加注解确保方法的安全性。
- 在config配置类(springsecu配置类)上加注解
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
加上注解后就是有的方法是只有特定的角色才能访问。
加上一个service层。
@Service
public class MethodService {
@PreAuthorize("hasRole('admin')")
public String admin(){
return "admin can have access";
}
@Secured("ROLB_user")
public String user() {
return "user can have access";
}
@PreAuthorize("hasAnyRole('admin','user')")
public String hello(){
return "everyone can have access";
}
}
在controller中加入相应的方法。
@GetMapping("/hi1")
public String hello1(){
return methodService.admin();
}
@GetMapping("/hi2")
public String hello2(){
return methodService.user();
}
@GetMapping("/hi3")
public String hello3(){
return methodService.hello();
}
admin角色登录之后,可以访问所有的url,但是在访问/hi2时会返回一个403,因为user()方法被限制了。
基于数据库认证
创建数据库User、Role、User-Role表。
编写实体类User和Role。
使用数据库作为SpringSecurity的用户时,用户类(user)要实现UserDetails接口。
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLB_" + role.getName()));
}
return authorities;
}
注意角色默认有前缀ROLB_,如果数据中的字段已经有前缀了就不用加前缀的拼接。
使用数据库作为SpringSecurity的用户时,服务类(userService)要实现UserDetailsService接口。
本文详细介绍SpringSecurity的使用,包括依赖配置、用户名密码手动配置、HTTP安全配置、方法安全、基于数据库认证等关键步骤。

1万+

被折叠的 条评论
为什么被折叠?



