SSM整合SpringSecurity
前言:介绍SpringSecurity,简单来说,你可以在这设置给需要保护的资源上一把锁,也可以给某些请求一把钥匙允许其访问。这里的锁指的是访问需要的权限或者角色。钥匙就是对应的权限或者角色。正如其官网图标。
引入pom依赖
<!-- SpringSecurity 对 Web 应用进行权限管理 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.10.RELEASE</version>
</dependency>
<!-- SpringSecurity 配置 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.10.RELEASE</version>
</dependency>
<!-- SpringSecurity 标签库 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.2.10.RELEASE</version>
</dependency>
编写自定义的配置类
@Configuration
@EnableWebSecurity
public class WebAppSercurityConfig extends WebSecurityConfigurerAdapter {
使用@Configuration注解把该类标记为配置类
使用@EnableWebSecurity:1: 加载了WebSecurityConfiguration配置类。2: 加载了AuthenticationConfiguration, 配置了认证信息。
在配置类中进行定制化
在配置类中重写 protected void configure(HttpSecurity security) 方法,设置锁
@Override
protected void configure(HttpSecurity security) throws Exception {
security.authorizeRequests()
.antMatchers("/admin/to/login/page.html") // 放行登录页
.permitAll()
.antMatchers("/bootstrap/**") // 放行静态资源
.permitAll()
.antMatchers("/admin/get/page.html") //针对分页显示Admin数据设定访问控制
.access("hasRole('经理') or hasAuthority('user:get')") // 具有相应角色或者权限就能访问
.antMatchers("/admin/save.html")
.hasRole("经理")// 要求具备经理角色
.anyRequest()
.authenticated()
.and()
.formLogin()// 开启表单登录
.loginPage("/admin/to/login/page.html")// 登录页
.loginProcessingUrl("/security/do/login.html")// 验证登陆的地址
.defaultSuccessUrl("/admin/to/main/page.html")// 登陆成功后去的地址
.usernameParameter("loginAcct") // 自定义登录表单参数名 默认为:username
.passwordParameter("userPswd")// 自定义登录表单参数名 默认为:password
.and()
.logout() // 开启退出登录功能
.logoutUrl("/security/do/logout.html") // 退出登录请求
.logoutSuccessUrl("/admin/to/login/page.html") // 退出登陆后前往的地址
;
security.csrf().disable();// 禁用csrf功能
}
重写protected void configure(AuthenticationManagerBuilder auth)方法 分配钥匙
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 认证信息在内存中实现
/* auth.inMemoryAuthentication()
.withUser("zs").password("123").roles("ADMIN");*/
// 正式功能中使用基于数据库的认证
auth.userDetailsService(userdetaileservice).passwordEncoder(getbbryptPasswordEncoder());
}
错误解决
这时你在启动时,可能会报这样的错误:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available
错误分析
为什么会报这样的错:因为ssm中有两大容器
- 一个是spring的ioc容器:
ContextLoaderListener
- 一个是springmvc的ioc容器:
DispatcherServlet
在项目启动时:首先ContextLoaderListener
初始化,其次springSecurityFilterChain
初始化,最后DispatcherServlet
初始化;
springSecurityFilterChain
初始化时会默认去寻找springmvc的ioc容器扫描配置类
解决方案:
将springmvc的ioc容器和spring的ioc容器合二为一。
做法:
在web.xml文件中注释掉初始化ContextLoaderListener
的配置
<!--配置spring 初始化器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!–<param-value>classpath:application*.xml</param-value>–>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
然后在springmvc初始化文件中加入 <import resource="classpath:application*.xml"/>
初始化spring的ioc容器的配置
此时你的项目是能够运行的。
分配权限——数据库版
1、在springsercurity中重写父类方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 正式功能中使用基于数据库的认证 auth.userDetailsService(userdetaileservice).passwordEncoder(getbbryptPasswordEncoder());
}
2、建立数据库(建库语句)
3、装配数据源
- 写配置文件,在初始化的时候放入ioc容器中
- 进行自动装配
4、写一个userDetailsService的实现类
@Service
public class CrowdUserDetailService implements UserDetailsService {
@Autowired
private AdminService adminService;
@Autowired
private RoleService roleService;
@Autowired
private AuthService authService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据username查询出admin对象
Admin admin=adminService.selectByLoginAcct(username);
// 根据adminid取出用户拥有的角色和权限
Integer adminId=admin.getId();
List<Role> assignedRoleList = roleService.getAssignedRoleList(adminId);
List<String> assignedAuthNameByAdminId = authService.getAssignedAuthNameByAdminId(adminId);
List<GrantedAuthority> authorities=new ArrayList<>();
// 把角色和权限进行循环封装存入
for (Role role : assignedRoleList) {
String name="ROLE_"+role.getName();
SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority(name);
authorities.add(simpleGrantedAuthority);
}
for (String s : assignedAuthNameByAdminId) {
SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority(s);
authorities.add(simpleGrantedAuthority);
}
SercurityAdmin sercurityAdmin=new SercurityAdmin(admin,authorities);
return sercurityAdmin;
}
}
- 在实现类中根据用户名查询出用户,比较密码
- 分配权限和角色
5、编写User子类
public class SercurityAdmin extends User {
private Admin originalamin;
public SercurityAdmin(Admin admin, List<GrantedAuthority> list){
super(admin.getLoginAcct(),admin.getUserPswd(),list);
this.originalamin=admin;
// 将密码擦除,提升系统整体安全性
this.originalamin.setUserPswd(null);
}
public Admin getOriginalamin() {
return originalamin;
}
public void setOriginalamin(Admin originalamin) {
this.originalamin = originalamin;
}
}
权限控制——页面元素
1、引入标签库
<%@taglib prefix="sercurity" uri="http://www.springframework.org/security/tags" %>
2、设置相应的权限或者角色,登入用户有相应的角色或者权限才能访问
<sercurity:authorize access="hasRole('经理')">
<div class="col-xs-6 col-sm-3 placeholder">
<img data-src="holder.js/200x200/auto/sky" class="img-responsive" alt="Generic placeholder thumbnail">
<h4>Label</h4>
<span class="text-muted">Something else</span>
</div>
</sercurity:authorize>