@Service
public class UserService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//此处根据用户名在数据库中查找,这里不再查找,直接返回一个org.springframework.security.core.userdetails.User对象(如果是自定义的User类,需要实现UserDetails接口)
return new User(username,new BCryptPasswordEncoder().encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
@Configuration
public class BrowserSecurity extends WebSecurityConfigurerAdapter {
//引入自定义UserDetailsService
@Autowired
private UserService userService;
//加密
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置内存认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
}
自定义User类实现该接口,该接口主要有如下方法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义登录页面登录</title>
</head>
<body>
<form action="/login" method="post">
<div class="form">
<h3>账户登录</h3>
<input type="text" placeholder="用户名" name="username" required="required" /></br>
<input type="password" placeholder="密码" name="password" required="required" />
<button type="submit">登录</button>
</div>
</form>
</body>
</html>
整体配置如下:
@Configuration
public class BrowserSecurity extends WebSecurityConfigurerAdapter {
//引入自定义UserDetailsService
@Autowired
private UserService userService;
//加密
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置内存认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
//配置HttpSecurity
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//授权配置
.antMatchers("/myLogin.html").permitAll().anyRequest().authenticated()
.and()
//表单配置
.formLogin().loginPage("/myLogin.html").loginProcessingUrl("/login")
.and()
//默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
.csrf().disable();
}
}
除了登录页面可以直接访问,其他请求需要跳转到登录页面完成认证后才可以访问
整体配置如下:
@Configuration
public class BrowserSecurity extends WebSecurityConfigurerAdapter {
//引入自定义UserDetailsService
@Autowired
private UserService userService;
//加密
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置内存认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
//配置HttpSecurity
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//授权配置
.antMatchers("/myLogin.html").permitAll().anyRequest().authenticated()
.and()
//表单配置
.formLogin().loginPage("/myLogin.html").loginProcessingUrl("/login")
.successHandler(new AuthenticationSuccessHandler() {
//登录成功返回一段json信息
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//Authentication authentication 包含用户登录信息
String name = authentication.getName();
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(200);
Map<String,Object> map = new HashMap<>();
map.put("status",200);
map.put("msg",name);
ObjectMapper mapper = new ObjectMapper();
out.write(mapper.writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
//登录失败,根据相关异常返回失败信息
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(401);
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","密码已过期");
}else{
map.put("msg","登录失败");
}
ObjectMapper mapper = new ObjectMapper();
out.write(mapper.writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
//默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
.csrf().disable();
}
}
@Component
public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(mapper.writeValueAsString(authentication));
}
}
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException {
}
}
@Autowired
private MyAuthenticationSucessHandler authenticationSucessHandler;
@Autowired
private MyAuthenticationFailureHandler authenticationFailureHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.successHandler(authenticationSucessHandler) // 处理登录成功
.failureHandler(authenticationFailureHandler) // 处理登录失败
}
登录成功
登录失败
原文:https://www.cnblogs.com/wuba/p/11827313.html