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,返回