如何创建一个spring security项目
-
写个demo很简单,创建springboot项目,添加web和security依赖
-
自己随便写个接口
public class HelloController { @GetMapping("/hello") public String helloController(){ return "hello security"; }
-
启动项目 localhost:8080/hello 自动重定向到login并显示登陆界面
-
用户名user,密码springboot自动生成,控制台复制即可
如何在配置用户名密码
- 在配置文件(application properties)中配置
spring.security.user.name=ajian
spring.security.user.password=123456
spring.security.user.roles=admin
- 在代码中配置
package com.example.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance(); //单例模式对象不能new出来,只能通过getInstance方法
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("123").roles("admin")
.and()
.withUser("laji").password("happy520").roles("user");
}
}
自定义安全配置,使得只有认证过的用户才可以访问到页面
package com.example.security.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.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance(); //单例模式对象不能new出来,只能通过getInstance方法
} //密码需要加密,后面解决。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("123").roles("admin")
.and()
.withUser("laji").password("happy520").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()开启登录配置
.antMatchers("/admin/**").hasRole("admin")//表示访问 /hello 这个接口,需要具备 admin 这个角色
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")//登录处理接口
.permitAll()
.and()
.csrf().disable();
}
}
controller里面也写相应的方法 postman进行测试
表单登陆详细配置
具体参数如下https://blog.csdn.net/yin380697242/article/details/51893397
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.*;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance(); //单例模式对象不能new出来,只能通过getInstance方法
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("123").roles("admin")
.and()
.withUser("laji").password("happy520").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()开启登录配置
.antMatchers("/admin/**").hasRole("admin")//表示访问 /hello 这个接口,需要具备 admin 这个角色
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")//登录处理接口
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
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)); //把一个对象转成json字符串
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",401);
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","密码过期,登陆失败");
}
out.write(new ObjectMapper().writeValueAsString(map)); //把一个对象转成json字符串
out.flush();
out.close();
}
})
.permitAll()
.and()
.csrf().disable();
}
}
注销登录配置
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("status",200);
map.put("msg","注销登陆成功");
out.write(new ObjectMapper().writeValueAsString(map)); //把一个对象转成json字符串
out.flush();
out.close();
}
})
解决密码加密问题
先用BCryptPasswordEncoder生成,真实的开发情况肯定是用户通过这个util加密后存入数据库的,这里只模拟这种情况
@Test
void contextLoads() {
for(int i=0;i<10;i++){
BCryptPasswordEncoder bcencoder = new BCryptPasswordEncoder();
System.out.println(bcencoder.encode("123"));
}
}
把打印出来的密码换掉原来的明文密码在securityConfig里面
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("$2a$10$Kl3o4ubuwdyC8VAMI4CE1.SZSBgEcGm1ap8h6ZGUhywrIi6ZCKec2").roles("admin")
.and()
.withUser("laji").password("$2a$10$.7e3IGQqXP1vU69lY1/DWeOVRm/aFa/DYMToTZcwZtpX3eFTbFTSS").roles("user");
}
方法安全(某些角色才能调用某些方法)
securityconfig上
//配置类上加注解
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {.......}
加入service methodSerice类
package com.example.security.serivce;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MethodService {
@PreAuthorize("hasRole('admin')")
public String admin(){
return "hello admin";
}
@Secured("ROLE_user")
public String user(){
return "hello user";
}
@PreAuthorize("hasAnyRole('admin','user')")
public String hello(){
return "hello hello";
}
}
加一下controller里面的接口
@GetMapping("/admin")
public String admin(){
return methodService.admin();
}
@GetMapping("/user")
public String user(){
return methodService.user();
}
@GetMapping("/hello1")
public String hello(){
return methodService.hello();
}
测试一下
简单入门案例github地址 链接