Spring Security是Spring生态系统中的安全框架,本文将深入探讨其核心概念和实践应用。
基础配置
Maven依赖
1
2
3
4
5
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId> spring-boot-starter-security</artifactId>
<version> 1.5.6.RELEASE</version>
</dependency>
基本配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure ( HttpSecurity http ) throws Exception {
http
. authorizeRequests ()
. antMatchers ( "/" , "/home" ). permitAll ()
. antMatchers ( "/admin/**" ). hasRole ( "ADMIN" )
. anyRequest (). authenticated ()
. and ()
. formLogin ()
. loginPage ( "/login" )
. permitAll ()
. and ()
. logout ()
. permitAll ();
}
@Autowired
public void configureGlobal ( AuthenticationManagerBuilder auth ) throws Exception {
auth
. inMemoryAuthentication ()
. withUser ( "user" ). password ( "password" ). roles ( "USER" )
. and ()
. withUser ( "admin" ). password ( "password" ). roles ( "USER" , "ADMIN" );
}
}
用户认证
自定义UserDetailsService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository ;
@Override
public UserDetails loadUserByUsername ( String username ) throws UsernameNotFoundException {
User user = userRepository . findByUsername ( username )
. orElseThrow (() -> new UsernameNotFoundException ( "User not found" ));
return new org . springframework . security . core . userdetails . User (
user . getUsername (),
user . getPassword (),
getAuthorities ( user . getRoles ())
);
}
private Collection <? extends GrantedAuthority > getAuthorities ( Set < Role > roles ) {
return roles . stream ()
. map ( role -> new SimpleGrantedAuthority ( role . getName ()))
. collect ( Collectors . toList ());
}
}
密码加密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class PasswordEncoderConfig {
@Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder ();
}
}
@Service
public class UserService {
@Autowired
private PasswordEncoder passwordEncoder ;
public void createUser ( User user ) {
user . setPassword ( passwordEncoder . encode ( user . getPassword ()));
userRepository . save ( user );
}
}
权限控制
方法级安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@EnableGlobalMethodSecurity ( prePostEnabled = true )
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
@Service
public class UserService {
@PreAuthorize ( "hasRole('ADMIN')" )
public void deleteUser ( Long userId ) {
// 删除用户的逻辑
}
@PostAuthorize ( "returnObject.username == authentication.name" )
public User getCurrentUserInfo () {
// 获取用户信息的逻辑
}
}
自定义权限评估器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission ( Authentication auth , Object targetDomainObject , Object permission ) {
if (( auth == null ) || ( targetDomainObject == null ) || ! ( permission instanceof String )) {
return false ;
}
String targetType = targetDomainObject . getClass (). getSimpleName (). toUpperCase ();
return hasPrivilege ( auth , targetType , permission . toString (). toUpperCase ());
}
private boolean hasPrivilege ( Authentication auth , String targetType , String permission ) {
for ( GrantedAuthority grantedAuth : auth . getAuthorities ()) {
if ( grantedAuth . getAuthority (). startsWith ( targetType ) &&
grantedAuth . getAuthority (). contains ( permission )) {
return true ;
}
}
return false ;
}
}
JWT集成
JWT配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Configuration
public class JwtConfig {
@Value ( "${jwt.secret}" )
private String secret ;
@Value ( "${jwt.expiration}" )
private Long expiration ;
@Bean
public JwtTokenUtil jwtTokenUtil () {
return new JwtTokenUtil ( secret , expiration );
}
}
public class JwtTokenUtil {
private String secret ;
private Long expiration ;
public String generateToken ( UserDetails userDetails ) {
Map < String , Object > claims = new HashMap <> ();
return Jwts . builder ()
. setClaims ( claims )
. setSubject ( userDetails . getUsername ())
. setIssuedAt ( new Date ())
. setExpiration ( new Date ( System . currentTimeMillis () + expiration ))
. signWith ( SignatureAlgorithm . HS512 , secret )
. compact ();
}
}
JWT认证过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil ;
@Autowired
private UserDetailsService userDetailsService ;
@Override
protected void doFilterInternal ( HttpServletRequest request ,
HttpServletResponse response ,
FilterChain chain ) throws ServletException , IOException {
String token = extractToken ( request );
if ( token != null && jwtTokenUtil . validateToken ( token )) {
String username = jwtTokenUtil . getUsernameFromToken ( token );
UserDetails userDetails = userDetailsService . loadUserByUsername ( username );
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken ( userDetails , null , userDetails . getAuthorities ());
SecurityContextHolder . getContext (). setAuthentication ( authentication );
}
chain . doFilter ( request , response );
}
}
OAuth2集成
OAuth2配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager ;
@Override
public void configure ( ClientDetailsServiceConfigurer clients ) throws Exception {
clients . inMemory ()
. withClient ( "client-id" )
. secret ( "client-secret" )
. authorizedGrantTypes ( "password" , "refresh_token" )
. scopes ( "read" , "write" )
. accessTokenValiditySeconds ( 3600 );
}
@Override
public void configure ( AuthorizationServerEndpointsConfigurer endpoints ) throws Exception {
endpoints
. authenticationManager ( authenticationManager )
. userDetailsService ( userDetailsService );
}
}
安全最佳实践
CSRF防护
1
2
3
4
5
6
7
8
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure ( HttpSecurity http ) throws Exception {
http . csrf ()
. csrfTokenRepository ( CookieCsrfTokenRepository . withHttpOnlyFalse ());
}
}
XSS防护
1
2
3
4
5
6
7
@Bean
public FilterRegistrationBean xssPreventFilter () {
FilterRegistrationBean registrationBean = new FilterRegistrationBean ();
registrationBean . setFilter ( new XSSFilter ());
registrationBean . addUrlPatterns ( "/*" );
return registrationBean ;
}
性能优化
缓存用户信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class CachingUserDetailsService implements UserDetailsService {
@Autowired
private Cache userCache ;
@Override
public UserDetails loadUserByUsername ( String username ) {
UserDetails user = userCache . get ( username );
if ( user == null ) {
user = loadUser ( username );
userCache . put ( username , user );
}
return user ;
}
}
总结
Spring Security提供了全面的安全解决方案,通过合理配置和使用其特性,可以构建安全可靠的企业级应用。
参考资料
Spring Security官方文档
Spring Security实战
OAuth 2.0实战
Licensed under CC BY-NC-SA 4.0