详解spring security 配置多个AuthenticationProvider

前言

发现很少关于spring security的文章,基本都是入门级的,配个UserServiceDetails或者配个路由控制就完事了,而且很多还是xml配置,国内通病...so,本文里的配置都是java配置,不涉及xml配置,事实上我也不会xml配置

spring security的大体介绍

spring security本身如果只是说配置,还是很简单易懂的(我也不知道网上说spring security难,难在哪里),简单不需要特别的功能,一个WebSecurityConfigurerAdapter的实现,然后实现UserServiceDetails就是简单的数据库验证了,这个我就不说了。

spring security大体上是由一堆Filter(所以才能在spring mvc前拦截请求)实现的,Filter有几个,登出Filter(LogoutFilter),用户名密码验证Filter(UsernamePasswordAuthenticationFilter)之类的,Filter再交由其他组件完成细分的功能,例如最常用的UsernamePasswordAuthenticationFilter会持有一个AuthenticationManager引用,AuthenticationManager顾名思义,验证管理器,负责验证的,但AuthenticationManager本身并不做具体的验证工作,AuthenticationManager持有一个AuthenticationProvider集合,AuthenticationProvider才是做验证工作的组件,AuthenticationManager和AuthenticationProvider的工作机制可以大概看一下这两个的java doc,然后成功失败都有相对应该Handler 。大体的spring security的验证工作流程就是这样了。

开始配置多AuthenticationProvider

首先,写一个内存认证的AuthenticationProvider,这里我简单地写一个只有root帐号的AuthenticationProvider

?

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

package com.scau.equipment.config.common.security.provider;

import org.springframework.security.authentication.AuthenticationProvider;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.AuthenticationException;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.authority.SimpleGrantedAuthority;

import org.springframework.security.core.userdetails.User;

import org.springframework.stereotype.Component;

import java.util.Arrays;

import java.util.List;

/**

* Created by Administrator on 2017-05-10.

*/

@Component

public class InMemoryAuthenticationProvider implements AuthenticationProvider {

private final String adminName = "root";

private final String adminPassword = "root";

//根用户拥有全部的权限

private final List<GrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("CAN_SEARCH"),

new SimpleGrantedAuthority("CAN_SEARCH"),

new SimpleGrantedAuthority("CAN_EXPORT"),

new SimpleGrantedAuthority("CAN_IMPORT"),

new SimpleGrantedAuthority("CAN_BORROW"),

new SimpleGrantedAuthority("CAN_RETURN"),

new SimpleGrantedAuthority("CAN_REPAIR"),

new SimpleGrantedAuthority("CAN_DISCARD"),

new SimpleGrantedAuthority("CAN_EMPOWERMENT"),

new SimpleGrantedAuthority("CAN_BREED"));

@Override

public Authentication authenticate(Authentication authentication) throws AuthenticationException {

if(isMatch(authentication)){

User user = new User(authentication.getName(),authentication.getCredentials().toString(),authorities);

return new UsernamePasswordAuthenticationToken(user,authentication.getCredentials(),authorities);

}

return null;

}

@Override

public boolean supports(Class<?> authentication) {

return true;

}

private boolean isMatch(Authentication authentication){

if(authentication.getName().equals(adminName)&&authentication.getCredentials().equals(adminPassword))

return true;

else

return false;

}

}

support方法检查authentication的类型是不是这个AuthenticationProvider支持的,这里我简单地返回true,就是所有都支持,这里所说的authentication为什么会有多个类型,是因为多个AuthenticationProvider可以返回不同的Authentication。

public Authentication authenticate(Authentication authentication) throws AuthenticationException 方法就是验证过程。

如果AuthenticationProvider返回了null,AuthenticationManager会交给下一个支持authentication类型的AuthenticationProvider处理。

另外需要一个数据库认证的AuthenticationProvider,我们可以直接用spring security提供的DaoAuthenticationProvider,设置一下UserServiceDetails和PasswordEncoder就可以了

?

1

2

3

4

5

6

7

@Bean

DaoAuthenticationProvider daoAuthenticationProvider(){

DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();

daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());

daoAuthenticationProvider.setUserDetailsService(userServiceDetails);

return daoAuthenticationProvider;

}

最后在WebSecurityConfigurerAdapter里配置一个含有以上两个AuthenticationProvider的AuthenticationManager,依然重用spring security提供的ProviderManager

?

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

package com.scau.equipment.config.common.security;

import com.scau.equipment.config.common.security.handler.AjaxLoginFailureHandler;

import com.scau.equipment.config.common.security.handler.AjaxLoginSuccessHandler;

import com.scau.equipment.config.common.security.provider.InMemoryAuthenticationProvider;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.ProviderManager;

import org.springframework.security.authentication.dao.DaoAuthenticationProvider;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;

import org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.builders.WebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.authority.SimpleGrantedAuthority;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.Arrays;

import java.util.List;

/**

* Created by Administrator on 2017/2/17.

*/

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

UserDetailsService userServiceDetails;

@Autowired

InMemoryAuthenticationProvider inMemoryAuthenticationProvider;

@Bean

DaoAuthenticationProvider daoAuthenticationProvider(){

DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();

daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());

daoAuthenticationProvider.setUserDetailsService(userServiceDetails);

return daoAuthenticationProvider;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http

.csrf().disable()

.rememberMe().alwaysRemember(true).tokenValiditySeconds(86400).and()

.authorizeRequests()

.antMatchers("/","/*swagger*/**", "/v2/api-docs").permitAll()

.anyRequest().authenticated().and()

.formLogin()

.loginPage("/")

.loginProcessingUrl("/login")

.successHandler(new AjaxLoginSuccessHandler())

.failureHandler(new AjaxLoginFailureHandler()).and()

.logout().logoutUrl("/logout").logoutSuccessUrl("/");

}

@Override

public void configure(WebSecurity web) throws Exception {

web.ignoring().antMatchers("/public/**", "/webjars/**", "/v2/**", "/swagger**");

}

@Override

protected AuthenticationManager authenticationManager() throws Exception {

ProviderManager authenticationManager = new ProviderManager(Arrays.asList(inMemoryAuthenticationProvider,daoAuthenticationProvider()));

//不擦除认证密码,擦除会导致TokenBasedRememberMeServices因为找不到Credentials再调用UserDetailsService而抛出UsernameNotFoundException

authenticationManager.setEraseCredentialsAfterAuthentication(false);

return authenticationManager;

}

/**

* 这里需要提供UserDetailsService的原因是RememberMeServices需要用到

* @return

*/

@Override

protected UserDetailsService userDetailsService() {

return userServiceDetails;

}

}

基本上都是重用了原有的类,很多都是默认使用的,只不过为了修改下行为而重新配置。其实如果偷懒,直接用一个UserDetailsService,在里面做各种认证也是可以的~不过这样就没意思了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/scau-chm/p/6836748.html?utm_source=tuicool&utm_medium=referral

本文链接:https://my.lmcjl.com/post/20305.html

展开阅读全文

4 评论

留下您的评论.