Spring Security身份认证之UserDetailsService
SecurityConfig
package com.waylau.spring.boot.blog.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Spring Security 配置类.
*
* @since 1.0.0 2017年3月8日
* @author <a href="https://waylau.com">Way Lau</a>
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用方法安全设置
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String KEY = "waylau.com";
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 使用 BCrypt 加密
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder); // 设置密码加密方式
return authenticationProvider;
}
/**
* 自定义配置
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/css/**", "/js/**", "/fonts/**", "/index").permitAll() // 都可以访问
.antMatchers("/h2-console/**").permitAll() // 都可以访问
.antMatchers("/admins/**").hasRole("ADMIN") // 需要相应的角色才能访问
.and()
.formLogin() //基于 Form 表单登录验证
.loginPage("/login").failureUrl("/login-error") // 自定义登录界面
.and().rememberMe().key(KEY) // 启用 remember me
.and().exceptionHandling().accessDeniedPage("/403"); // 处理异常,拒绝访问就重定向到 403 页面
http.csrf().ignoringAntMatchers("/h2-console/**"); // 禁用 H2 控制台的 CSRF 防护
http.headers().frameOptions().sameOrigin(); // 允许来自同一来源的H2 控制台的请求
}
/**
* 认证信息管理
* @param auth
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService, UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
UserController
/**
* 新建用户
* @param user
* @param result
* @param redirect
* @return
*/
@PostMapping
public ResponseEntity<Response> create(User user, Long authorityId) {
List<Authority> authorities = new ArrayList<>();
authorities.add(authorityService.getAuthorityById(authorityId));
user.setAuthorities(authorities);
if(user.getId() == null) {
user.setEncodePassword(user.getPassword()); // 加密密码
}else {
// 判断密码是否做了变更
User originalUser = userService.getUserById(user.getId());
String rawPassword = originalUser.getPassword();
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encodePasswd = encoder.encode(user.getPassword());
boolean isMatch = encoder.matches(rawPassword, encodePasswd);
if (!isMatch) {
user.setEncodePassword(user.getPassword());
}else {
user.setPassword(user.getPassword());
}
}
try {
userService.saveUser(user);
} catch (ConstraintViolationException e) {
return ResponseEntity.ok().body(new Response(false, ConstraintViolationExceptionHandler.getMessage(e)));
}
return ResponseEntity.ok().body(new Response(true, "处理成功", user));
}
/**
* @author Administrator
*
*/
public class ConstraintViolationExceptionHandler {
/**
* 获取批量异常信息
* @param e
* @return
*/
public static String getMessage(ConstraintViolationException e) {
List<String> msgList = new ArrayList<>();
for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
msgList.add(constraintViolation.getMessage());
}
String messages = StringUtils.join(msgList.toArray(), ";");
return messages;
}
}
header.html(没有该令牌不能操作方法,只有POST提交才自动有令牌)
<!-- CSRF -->
<meta name="_csrf" th:content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
main.js
// 删除用户
$("#rightContainer").on("click",".blog-delete-user", function () {
// 获取 CSRF Token
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
$.ajax({
url: "/users/" + $(this).attr("userId") ,
type: 'DELETE',
beforeSend: function(request) {
request.setRequestHeader(csrfHeader, csrfToken); // 添加 CSRF Token
},
success: function(data){
if (data.success) {
// 从新刷新主界面
getUersByName(0, _pageSize);
} else {
toastr.error(data.message);
}
},
error : function() {
toastr.error("error!");
}
});
});