Spring security
Spring security解決方法是
添加校验token
由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再运行CSRF攻击。这种数据通常是窗体中的一个数据项。服务器将其生成并附加在窗体中,其内容是一个伪随机数。当客户端通过窗体提交请求时,这个伪随机数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验token的值为空或者错误,拒绝这个可疑请求
開啟csrf
有csrf用隱藏域
關閉csrf
則沒有_csrf隱藏域
@RestController
public class HelloController {
//只有dba能訪問
@GetMapping("/db/hello")
public String DBHello(){return "db hello";}
//只有admin能訪問
@GetMapping("/admin/hello")
public String adminHello(){return "admin hello";}
//只有user能訪問
@GetMapping("/user/hello")
public String userHello(){return "user hello";}
//任何人都能訪問
@GetMapping("/hello")
public String Hello(){return "hello world";}
}
如果硬加上ROLE_
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* 配置三個用戶
* root 具備ADMIN DBA
* admin 具備 ADMIN USER
* sang USER
*/
auth.inMemoryAuthentication()
.withUser("root").password("123").roles("ADMIN","DBA")
.and()
.withUser("admin").password("123").roles("ADMIN","USER")
.and()
.withUser("sang").password("123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// /hello任何人都可訪問
.antMatchers("/hello").permitAll()
//.hasRole會自動加上ROLE_ 所以腳色名稱必須為ROLE_db
//只有admin
.antMatchers("/db/**").hasRole("db").anyRequest().authenticated()
//只有dba
.antMatchers("/admin/**").hasRole("admin").anyRequest().authenticated()
//只有user
.antMatchers("/user/**").hasRole("user").anyRequest().authenticated()
.and()
//登入接口任何人都能訪問
.formLogin().loginProcessingUrl("/login").permitAll()
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req,
HttpServletResponse resp,
Authentication auth)
throws IOException {
Object principal = auth.getPrincipal();
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
resp.setStatus(200);
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", principal);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
httpServletResponse.setStatus(401);
Map<String, Object> map = new HashMap<>();
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", "登入失敗");
}
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
.csrf()
.disable();
}
}
持久化保存用戶與腳色
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
}
@Component
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.findByName(s);
if(user == null)
throw new UsernameNotFoundException("找不到帳戶");
user.setRoles(roleMapper.findById(user.getId()));
System.out.println(user);
return user;
}
}
在
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
}
.........
測試
導入依賴
```xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest
class DemoApplicationTests {
@Autowired
UserMapper userMapper;
@Autowired
UserService userService;
@Autowired
RoleMapper roleMapper;
@Autowired
WebApplicationContext wac;
MockMvc mockMvc;
@Test
@WithMockUser(value = "miku" ,password = "1")
public void helloControllerTest() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders
.get("/db/hello"))
// .get("/hello"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
System.out.println(mvcResult.getResponse().getContentAsString());
}
}