springSecurity属于spring的一个安全工具,为我们的应用程序做权限控制,spring cloud security就是基于springSecurity的一套安全工具包。下面我们就来讲解一下springBoot应该如何集成springSecurity。
假设此时你已经配置好了一个springBoot项目,请参考:https://blog.csdn.net/qq_35689573/article/details/80808726,并可以正常启动了,那只需要在pom.xml文件中加入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
maven项目,写完别忘了右键项目,maven,reimport一下,我们在lib中看到security存在之后才是真正的导入了。
下面启动项目,观察启动日志:
07b25e71-7a9a-42c7-ba6b-845150947dc2是登录密码,此时我们随意访问该项目的任一路径会发现spring不允许,让我们先去进行权限验证:
User可以用springSecurity的默认用户user,Password要用我们上面的随机密码07b25e71-7a9a-42c7-ba6b-845150947dc2,登录成功。我们也可以通过在application.properties或application.yml中进行配置:
spring.security.user.name=hxj
spring.security.user.password=hxj123
至此简单的集成springSecurity我们已经完成了,但是实际项目中肯定不能这么敷衍,那我们会怎么做呢?
首先我们需要知道两个接口:UserDetailsService和WebSecurityConfigurerAdapter,UserDetailsService里面只有一个方法:
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
顾名思义就是通过用户名加载用户并返回一个UserDetails对象,
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
UserDetails里面封装了用户的一些基本信息,如用户名,用户密码,用户权限集合之类的。
WebSecurityConfigurerAdapter这是一个抽象类,权限配置适配器,所有用户登录时做的权限处理应该都在这里面。
下面我们先来实现UserDetailsService:
import com.example.springBootDemo.config.datasource.DaoHelper;
import com.example.springBootDemo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
@Component
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private DaoHelper daoHelper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = (User)daoHelper.queryOne("user.getUserByName",username);
return new org.springframework.security.core.userdetails.User(username,user.getPassword(),AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole()));
}
}
我们通过username从数据库中查询出对应的用户并把它强转成我们自定义的User对象,从这个User对象中提取信息,最终返回一个UserDetails对象。
再来看WebSecurityConfigurerAdapter:
@Configuration
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
/**
* 将我们在后台查询出来的用户信息配置成bean交给springSecurity的权限适配器
* */
@Bean
public UserDetailsService userDetailsService(){
return new MyUserDetailsService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
}
/**
* 对请求路径中带css,img,js的请求内容不进行权限拦截
* 根据实际情况合理增删
* */
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**","/img/**","/js/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().and().authorizeRequests()
.anyRequest().authenticated()
//登录路径,对应LoginController中的signIn方法,我们可以在这个方法中添加我们在进入登录页面前的一些逻辑
.and().formLogin().loginPage("/signIn")
//跳转到login页面,登录成功后默认跳转到index
.loginProcessingUrl("/login").defaultSuccessUrl("/index",true)
//登录失败跳转页面
.failureUrl("/signIn?error").permitAll()
//失效session跳转路径
.and().sessionManagement().invalidSessionUrl("/signIn")
//session失效时间
.and().rememberMe().tokenValiditySeconds(1209600)
//掉线之后的跳转路径
.and().logout().logoutSuccessUrl("/signIn").permitAll()
.and().csrf().disable();
}
}
MyWebSecurityConfigurerAdapter中主要重写了WebSecurityConfigurerAdapter中的三个方法,定义了登录方法和登录页面的一下权限控制。
LoginController:
@Controller
public class LoginController {
@RequestMapping("signIn")
public String signIn(){
return "/login";
}
@RequestMapping("index")
public String index(){
return "/index";
}
}
login.html页面(我用的是thymleaf模板引擎):
图中圈中的地方注意一下,“/login”是在MyWebSecurityConfigurerAdapter中定义好的,其他都是springSecurity默认的。
访问:http://localhost:8080/index,会发现直接被拦截跳转到了http://localhost:8080/signIn:
点击登录,观察后台日志:
是因为我们一般存在数据库中的密码是加密的,但是我们在这里没有设置解密方式,所以我们还需要在MyWebSecurityConfigurerAdapter添加如下代码
/**
* 定义解码器
* */
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
并将定义的密码器注入到
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
此时我们再次访问http://localhost:8080/signIn,输入账号密码之后成功登入系统。
我们也可以自己定义加密规则:
@Component
public class MypasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
//定义加密规则并返回加密后的密码
return charSequence.toString();//此处我们就不加密了,直接返回明文
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return charSequence.equals(s);//上面没有加密,此处也就不用解密了
}
}
并注入MyWebSecurityConfigurerAdapter中:
/**
* 定义解码器
* */
@Bean
public PasswordEncoder passwordEncoder(){
return new MypasswordEncoder();
}
此时我们将数据库中的密码换成明文,登录成功。至此springSecurity的简单应用完成,其他配置请参考官方文档:
http://www.mossle.com/docs/springsecurity3/html/springsecurity.html