导读
在上一篇文章中对Spring Boot 集成Shrio做了一个简单的介绍,这篇文章中主要围绕Spring Boot 集成 Spring Security展开,文章末尾附有学习资料。
快速上手:
1.引入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.实现一个简单的用户权限类
用户权限功能的设计不是本篇文章的重点,这里以一个简单的例子作为演示,需要创建两个实体类一个枚举类
用户类:
@JsonIgnoreProperties(value = { "hibernateLazyInitializer","password" ,"new"})
@DynamicUpdate
@Entity
public class User extends AbstractPersistable<Long> {
private static final long serialVersionUID = 2080627010755280022L;
private String userName;
@Column(unique = true, updatable = false)
private String loginName;
private String password;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
/**省略get/set**/
}
角色类别:
public enum RoleType {
//級別从高到低 ADMIN->USER
ADMIN,//管理员
USER//普通用户
}
角色类:
@Entity
public class Role extends AbstractPersistable<Long> {
private static final long serialVersionUID = -856234002396786101L;
@Enumerated(EnumType.STRING)
@Column(name = "role_name", unique = true)
private RoleType roleType;
}
3.定制自己的配置
首先需要从数据库中查询出来用户数据交给Spring Security这里有两种主要的方式:
AuthenticationProvider&&UserDetailsService两种方式的介绍:
Spring Security认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。
a.实现UserDetailsService 接口
public class CustomUserDetailsService implements UserDetailsService {
@Autowired UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByLoginName(username);
if(user == null){
throw new UsernameNotFoundException("not found");
}
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(user.getRole().name()));
System.err.println("username is " + username + ", " + user.getRole().name());
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), authorities);
}
}
将自己的配置托管给Sprng 管理,Security为我们提供了WebSecurityConfigurerAdapter 我们只需要根据自己的需要进行继承重写即可
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/admin")
.permitAll()
.and()
.logout()
.permitAll();
}
}
b.实现 AuthenticationProvider接口
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(CustomAuthenticationProvider.class);
@Autowired
private UserRepository userRepository;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String loginName = authentication.getName();
String password = authentication.getCredentials().toString();
List<GrantedAuthority> grantedAuths = new ArrayList<>();
if (vaildateUser(loginName, password, grantedAuths)) {
Authentication auth = new UsernamePasswordAuthenticationToken(loginName, password, grantedAuths);
return auth;
} else {
return null;
}
}
public boolean vaildateUser(String loginName, String password, List<GrantedAuthority> grantedAuths) {
User user = userRepository.findByLoginName(loginName);
if (user == null || loginName == null || password == null) {
return false;
}
if (user.getPassword().equals(SHA.getResult(password)) && user.getUserStatus().equals(UserStatus.NORMAL)) {
Set<Role> roles = user.getRoles();
if (roles.isEmpty()) {
grantedAuths.add(new SimpleGrantedAuthority(RoleType.USER.name()));
}
for (Role role : roles) {
grantedAuths.add(new SimpleGrantedAuthority(role.getRoleType().name()));
logger.debug("username is " + loginName + ", " + role.getRoleType().name());
}
return true;
}
return false;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
将配置托管给Spring
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/admin")
.permitAll()
.and()
.logout()
.permitAll();
}
}
4.添加角色验证
我们将用户分成了管理员与普通用户,用户页面对用户与管理可见,管理员页面只对管理员可见
@Controller
public class UserController {
PreAuthorize("hasAnyAuthority('ADMIN','USER')")
@GetMapping("/user")
public String user(){
return "user";
}
@PreAuthorize("hasAnyAuthority('ADMIN')")@
@GetMapping("/admin")
public String admin(){
return "admin";
}
}
Spring Security虽然要比Apache Shiro功能强大,但作为Spring 自家的应用与Spring 整合确实非常简单,同样Spring Security 学习成本要比Apache Shiro高。
结语
这篇文章是匆忙中挤时间赶工出来的产物,有些地方也许写的有些问题,欢迎提出反馈。下篇文章打算用之前所学的技术做一个简单的项目,正在想做什么,欢迎提出建议。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。