第一步肯定是添加引用的包。
org.springframework.security
spring-security-web
5.0.1.RELEASE
org.springframework.security
spring-security-config
5.0.1.RELEASE
javax.annotation
jsr250-api
1.0
第二步肯定是从web启动这个框架。
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
注意:如果有spring的话,要配置在一块。
其实就是在配置spring的基础上,扫描文件的时候顺便把spring security的xml文件扫描进来就行了。本质就是加一行字的事,很简单
contextConfigLocation
classpath:applicationContext.xml
classpath:spring-security.xml
org.springframework.web.context.ContextLoaderListener
简单配置(就是将用户名写死在内存中,不连接数据库,进行一个简单的认证):
登录页面框架已经自带。
我们就规定它要对哪些页面进行安全验证就行了。
到此为止,最简单的功能已经配置完成啦。能够直接运行项目。正常的话会看到权限不足的提示,然后根据配置的用户名登录就好了。
有了基础配置,那么接下来配置得更细致一点
不使用Spring Security自带的登录页面,添加自己的登录页面
↑这个标签上一步已经写过了
现在要做的是在这个标签加新东西。
然后自己创建一个页面,填入对应的提交地址,传入对应的用户名和密码,框架会自进行验证。是否和文件里配置的一致。
注意的是需要放行登录页面以及登录失败页面。
SpringSecurity提供:
UserDetails接口 用户的信息 (自带,不需要写)
GrantedAuthority接口 权限 (自带,不需要写)
UserDetailsService接口 判断用户
关于UserDetails接口,框架自带一个名叫User的类。我们就不需要动手自己写了。
关于GrantedAuthority接口,框架也带有个叫SimpleGrantedAuthority的类,我们也不需要自己写。当然你想自己动手也行。
框架自带实现UserDetails接口的User类如下:
public class User implements UserDetails, CredentialsContainer {
private static final long serialVersionUID = 500L;
private String password; //密码
private final String username; //用户名
private final Set authorities; //权限名称集合
private final boolean accountNonExpired; //是否有效
private final boolean accountNonLocked; //是否锁定
private final boolean credentialsNonExpired; //认证是否过期
private final boolean enabled; //是否激活
框架自带的实现了GrantedAuthority接口的SimpleGrantedAuthority的类如下:
public final class SimpleGrantedAuthority implements GrantedAuthority {
private final String role; //权限名称
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return new User(用户名String,密码String,权限集合Set);
}
实际上↓
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
TBuserServiceI tBuserService;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
TBuser tBuser = tBuserService.queryOneByUserName(s);
Set roleSet = new HashSet();
for (String role:tBuser.getRoles()
) {
roleSet.add(new SimpleGrantedAuthority(role));
}
User user = null;
if(tBuser!=null){
user = new User(tBuser.getUsername(),tBuser.getPassword(),roleSet);
return user;
}else{
return null;
}
}
代码写好了,就开始配置。记得要在service上标记@Service
接着切换到spring-security.xml 修改先前配置的标签。
因为先前配置,用户名和密码是写死在文件里的,因为现在有数据库了。删掉就行。
在标签里配置属性user-service-ref 对应的UserDetailsService接口实现类
spring-security规定验证用户名和密码时,必须要配置加密类。
加密类就选对应的加密类,这里暂时就选择NoOpPasswordEncoder这个加密类(代表不加密)
配置结果如下:
先前是使用数据库明文存储验证的密码(未加密),现在来改成数据库存储加密后的密码。
spring-security自带了几个加密类。这里使用的是bcrypt加密方式。加密后长度为60位。
在spring-security.xml配置指定的加密类bean。
与第5步类似
只是配置加密类从NoOpPasswordEncoder(不加密)换成BCryptPasswordEncoder(bcrypt加密)
在spring-security.xml配置加密方式。(与第5步一样的配置)
存储用户密码的时候也要使用这个加密类
@Autowired
PasswordEncoder passwordEncoder;
@Override
public void add(TBuser tBuser) {
tBuser.setUserid(UUIDUtils.getUUID32());
tBuser.setPassword(passwordEncoder.encode(tBuser.getPassword()));
tBuserMapper.insert(tBuser);
}
存密码的时候,和读取密码的时候,用的都是同一套加密类。所以就能够正常读出来。
在此之前,先注意一下名称规范。
官方文档这样说,在权限名称前面需要加ROLE_前缀。例如USER要写成ROLE_USER
不然呢xml文件就会解析错误,我试了,是真的。
官方文档 46.3.3 What does “ROLE_” mean and why do I need it on my role names? >https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/reference/htmlsingle/#appendix-faq-role-prefix)
所以不仅仅xml配置权限时需要加前缀。最好统一存储的权限名称时也以ROLE_作为前缀。
错误
`正确
统一了权限名称的格式后 就可以开始配置
确认maven是否添加了JSR250依赖。
javax.annotation
jsr250-api
1.0
在spring-mvc.xml中配置开启注解权限控制
注意是spring-mvc.xml
注意是spring-mvc.xml
注意是spring-mvc.xml
说三遍!!
神坑:如果在spring-security.xml中配置这玩意,就会报错。
我也不知道为什么 ,大概是我配注解在controller上只有springMVC扫描得到??
报错代码500:An Authentication object was not found in the SecurityContext
在需要控制访问权限的方法前,加上权限控制注解。
@RolesAllowed(“ROLE_ADMIN”) 代表含有ROLE_ADMIN角色的用户可以访问。
@RolesAllowed({“ROLE_ADMIN”,“ROLE_USER”}) 代表多个用户可以访问
@PermitAll 代表任何角色可以访问(但是也需要登录)
@DenyAll 拒绝所有角色访问
例如:允许ROLE_ADMIN用户访问goRegister方法。
@RolesAllowed("ROLE_ADMIN")
@RequestMapping("goRegister")
public ModelAndView goRegister(){
ModelAndView mv = new ModelAndView();
mv.setViewName("user/register");
return mv;
}
配置完毕。再运行项目就会发现,只有ROLE_ADMIN权限的用户可以访问这个方法。
如果想在Controller中获得当前的用户信息怎么办?→可以配置这个Authentication 参数。
authentication代表当前认证对象,可以获得对象信息
@RequestMapping(value = "userInfo",method = RequestMethod.GET )
public ModelAndView userInfo(TBuser tBuser,Authentication authentication){
ModelAndView mv = new ModelAndView();
System.out.println("用户名=="+authentication.getName());
mv.setViewName("/user/userInfo");
return mv;
}