基于注解配置的spring mvc 4 + spring security 4实例与解析

本文详细介绍了Spring Security 4的主要功能,包括Authentication和Authorization,并解析了关键组件如SecurityContextHolder、Authentication接口、UsernamePasswordAuthenticationToken、AuthenticationProvider以及UserDetails和UserDetailsService。通过实例代码阐述了这些组件的工作原理及其相互关系,帮助读者深入理解Spring Security的配置与使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于spring security 4(以下简称SS) ,我们不能不否认,学习的成本是挺高的。如果光光是复制配置代码而不去理解SS的各个组件的实现原理和功能,那当然还是相当简单的一回事,因为配置的代码就那么几行

PS:本人不是大神,写博客只是为了增强记忆和理解,以下的内容都是本人通过大量学习SS官方文档和搜索stack overflow探索得来的观点

1.SS究竟主要实现什么功能?

SS实现了非常多的功能,但是概括地说,SS主要实现了Authentication和Authorization,中文译文为认证与授权。以下用一个生动的例子说明:
认证:就相当于去私人会所,进保安那一关,保安通过认脸(SS通过账户和密码等)确认你是否可以进入
授权:当然,私人会所里面也有森严的等级制度,一些抢手的红牌不是屌丝可以点的,当然就有些屌丝可以点红牌,也只允许陪酒和唱歌;而一些较牛的VIP,就有很高的权限可以为所欲为。

2. 认识各个关键部件

1. 基础上下文组件SecurityContextHolder
根据官网的译文,SecurityContextHolder是SS中最基础的类,主要用来储存认证信息、认证规则等信息。在SS 4之后的版本,几乎不需要我们手动去配置这个组件。但是我们还是来认识一下这个组件的具体原理:
SecurityContextHolder主要通过ThreadLocal来实现认证和授权信息的处理,这个组件如果要深究,请查看SS的源代码。
我们只要知道SecurityContextHolder有一个很重要的方法,那就是getContext(),方法返回SecurityContext 类,这个类同样有一个非常重要的getAuthentication(),返回的是一个Authentication类,这个类就是我们上文说到大名鼎鼎的认证接口。

2.认证接口Authentication,UsernamePasswordAuthenticationToken,AuthenticationProvide
值得注意的是Authentication继承了Principal接口,问题来了,什么是Principal,我们看看官方的说法:

This interface represents the abstract notion of a principal, which
can be used to represent any entity, such as an individual, a
corporation, and a login id.
这是一个虚拟的接口,可以代表任何的实体类

意思就是说,这个Principal什么都不干,只是一个纯粹的Object,开发者喜欢把它转换成什么就是什么。通常在SS里,一般会转换成UserDetails类,这个类等下再说。

回到Authentication接口,它有那么几个重要的方法值得注意:
getPrincipal():这个方法毫无疑问,返回的是一个Pincipal类,通常可以转换成UserDetails类
getCredentials():这个方法返回的是用户凭证,通常是密码
getAuthoritis():这个方法返回的是权限集合,例如{“ROLE_ADMIN”,”ROLE_EMPLOYER”}这样的集合。

实现了Authentication接口的具体类有以下几个,非常值得注意:

  • 一个是UsernamePasswordAuthenticationToken,它就是一个简单代表账号、密码和权限的东西。
  • 另外一个是AuthenticaitonManager和AuthenticationProvider,他们其实差别不大,就只拿AuthenticationProvider来讲好了。他们都有一个最重要的方法,那就是authenticate()方法

这个方法主要用来生成一个Authentication接口的实现类,好了相信很多童鞋看到这里都已经无法理解SS了,坦白说,我也是….

不过各位这样理解就好了,AuthenticationProvider是一个负责验证用户信息的类,如果通过认证,就返回一个UsernamePasswordAuthenticationToken类,说明认证成功。否则,抛出BadCredentialsException错误或者其他Exception。

3.UserDetails和UserDetailsService接口
这个接口的具体实现类是SS的org.springframework.security.core.userdetails.User类(以下简称User类),用来储存SS所需的用户信息。而UserDetails一般很少自己new出来,主要是通过UserDetailsService的loadUserByUserName(String name)来生成。在方法里,开发者可以通过任何途径将自己的用户类转换成SS的User类。

说了那么一大堆,我还是放出代码来比较好理解

SercurityConfig.java

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Bean
    public UserDetailsService userDetailsService(){
        return new MyUserDetailsService();
    }

    @Bean
    public MyAuthenticationProvider myAuthenticationProvider(){
        MyAuthenticationProvider provider = new MyAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService());
        return provider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // TODO Auto-generated method stub

        http
            .csrf()
                .disable()
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll();
    }
}

MyUserDetailsService

public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        System.out.println("UserDetails invoked");
        AppUser appUser = userDao.findUser(name);
        return new User(appUser.getName(),appUser.getPassword(),true,true,true,true,appUser.getAuthorities());
    }
}

MyAuthenticationProvider

    public class MyAuthenticationProvider extends DaoAuthenticationProvider{
        @Autowired
        private MyUserDetailsService uds;

        @Override
        public Authentication authenticate(Authentication auth) throws AuthenticationException {
            String requestName = auth.getName();
            String requestPass = auth.getCredentials().toString();
            UserDetails ud = uds.loadUserByUsername(requestName);

            //对比用户输入密码与数据库密码是否一致
            if (requestPass.equals(ud.getPassword())) {
                System.out.println("auth:user auth success");
                return new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(),
                        ud.getAuthorities());
            }
            throw new BadCredentialsException("Bad credentials");
        }

        @Override
        public boolean supports(Class<?> arg0) {
            // TODO Auto-generated method stub
            return true;
        }

涉及其他配置的代码太多了,有需要的自己下载哈。
http://download.youkuaiyun.com/download/selfreeyuan/10118873

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值