AuthenticationProvider
public interface AuthenticationProvider { Authentication authenticate(Authentication authentication) throws AuthenticationException; boolean supports(Class<?> authentication); }
该接口是开始认证的入口,传入用户输入的用户名密码到authenticate方法中进行验证,通过认证就返回用户完整的信息,若认证过程中有任何的错误,就直接抛出AuthenticationException。接下来实现一个简单的AuthenticationProvider:
1. 项目security.xml中添加如下代码:
<security:authentication-manager> <security:authentication-provider ref='myAuthenticationProvider'/> </security:authentication-manager>
2. 创建java类MyAuthenticationProvider 实现AuthenticationProvider接口:
@Component public class MyAuthenticationProvider implements AuthenticationProvider { @Override public boolean supports(Class<?> authentication) { return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); if (!"silentwu".equals(username)) { throw new UsernameNotFoundException("用户不存在"); } if (!"123456".equals(password)) { throw new BadCredentialsException("密码错误"); } return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); } }
用户在登录界面中输入用户名:silentwu 密码:123456 那么通过认证,否则返回对应的错误信息。
UserDetailsService
public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }
这个接口是认证过程的重要接口,只有一个方法,就是通过用户的唯一标识获取到用户的完整信息,包括密码和权限等。接着来看一个简单的实现:
1. 在security.xml中添加如下代码:
<security:authentication-manager> <security:authentication-provider user-service-ref='myUserDetailsService'/> </security:authentication-manager>
2. 创建Java类MyUserDetailsService ,实现UserDetailsService
@Component public class MyUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return new User("silentwu", "123456", Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); } }
在这个类中直接返回一个User对象,用户名是silentwu,密码是123456,对应用户输入的信息是否正确的检测,spring-security已经帮我们检测了
JdbcDaoImpl
通常情况下我们的用户数据都是存放到数据库中的,那么在用户登录的时候需要查询数据库进行验证,spring-security通过JdbcDaoImpl实现了这个功能,JdbcDaoImpl是UserDetailsService的一个子类。
<!--[if !supportLists]-->1.
1. <!--[endif]-->在数据库中执行如下代码:
CREATE TABLE users( username VARCHAR(50) NOT NULL PRIMARY KEY, PASSWORD VARCHAR(50) NOT NULL, enabled BOOLEAN NOT NULL ); CREATE TABLE authorities ( username VARCHAR(50) NOT NULL, authority VARCHAR(50) NOT NULL, CONSTRAINT fk_authorities_users FOREIGN KEY(username) REFERENCES users(username) ); CREATE UNIQUE INDEX ix_auth_username ON authorities (username,authority); insert into `authorities`(`username`,`authority`) values ('silentwu','ROLE_USER'); insert into `users`(`username`,`password`,`enabled`) values ('silentwu','12345',1);
2. 在security.xml中添加代码:
<security:authentication-provider> <security:jdbc-user-service data-source-ref="securityDataSource"/> </security:authentication-provider> </security:authentication-manager>
或者
<security:authentication-manager> <security:authentication-provider user-service-ref='myUserDetailsService'/> </security:authentication-manager> <bean id="myUserDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl"> <property name="dataSource" ref="securityDataSource"/> </bean>
这两种方式都是同样的效果
这样JdbcDaoImpl配置就完成了,很简单。
原理:
首先通过用户提交的用户名查询出用户信息,若没有查询到用户,那么就抛出UsernameNotFoundException
通过查询出来的用户去查询用户的权限表,获取用户的权限
创建UserDetails,返回