Spring Security是什么?
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
Spring security的使用:
首先引入Spring的核心jar包、SpringMvc的jar以及Security的jar包
http://download.csdn.net/download/evan_qb/10162753
也可以去官网下载
然后我们搭建SpringMvc和Spring Securitiy的环境
配置web.xml
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
cn.qblank.config.AppConfig
dispatcherServlet
/
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
package cn.qblank.controller.admin;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class UserController {
@RequestMapping(method = RequestMethod.GET,value = "/admin/users")
public String showAll(){
return "admin/users";
}
@RequestMapping(method = RequestMethod.GET,value = "/login")
public String show(){
return "login";
}
}
配置用户权限管理类实现UserDetailsService接口,输入加密的密码
给每个用户配置对应的权限
package cn.qblank.controller.admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserDetailServiceImpl implements UserDetailsService{
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 用户权限管理
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 当spring security需要用户详情时调用此方法,传入用户名
System.out.println("编码:123456 = " + passwordEncoder.encode("123456"));
System.out.println("编码:admin = " + passwordEncoder.encode("admin"));
switch(username){
case "user":
return new User("user", "$2a$10$spEZnJMseKZKynWV.X5/AuJjg.hpkeGJNx8ehCdARoNRpa3xLHMmW", "USER");
case "admin":
return new User("admin", "$2a$10$OvXZsFpWZlVYwvDa.Q9grOnxeWvAlaLPmtFTZCI7XM5dFfGlb1oVW", "ADMIN");
case "hr":
return new User("hr", "$2a$10$spEZnJMseKZKynWV.X5/AuJjg.hpkeGJNx8ehCdARoNRpa3xLHMmW", "ADMIN","HR");
default:
throw new UsernameNotFoundException( username+"不存在");
}
}
}
配置WebSecurityConfig
package cn.qblank.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity // 静态资源、json、校验等支持
//开启web security支持:应用bean容器里的WebSecurityConfigurer
@EnableGlobalMethodSecurity(securedEnabled = true,
//开启注解
prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserDetailsService userDetailsService;
/**
* 给用户、静态资源进行权限管理
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll() //给login的访问权
.antMatchers("/assets/**").permitAll() //给静态文件的访问权
.antMatchers("/admin/**").hasRole("ADMIN") //设置admin路径下的文件只能admin访问
.antMatchers("/**").authenticated().and() //给管理员普通赋予普通资源的权限
.formLogin() //用于表单
.loginPage("/login") //自定义表单提交页面
.and()
//添加记住功能
.rememberMe()
//开启remember Me的支持
.userDetailsService(userDetailsService)
//记住八小时
.tokenValiditySeconds(8*3600);
}
/**
* 使用BCryptPasswordEncoder管理密码
* @return
*/
@Bean
public PasswordEncoder passwordEncoder(){
System.out.println("WebSecurityConfig.passwordEncoder()");
return new BCryptPasswordEncoder();
}
}
重写构造方法,实现用户权限的添加
package cn.qblank.controller.admin;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
public class User extends org.springframework.security.core.userdetails.User{
public User(String username,String password,String... roles){
super(username, password, buildAuthorities(roles));
}
public static List buildAuthorities(String[] roles){
List authorities = new ArrayList<>();
System.out.println(roles);
for (String role : roles) {
//记住要拼接角色
authorities.add(new SimpleGrantedAuthority("ROLE_"+role));
}
return authorities;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
登录
例如我们现在访问admin路径下的employees如果用户没登录,就会跳转到登录界面
接下来我们登录admin用户
首先admin路径下的文件需要admin以上用户登录,而getAll()方法必须由hr用户才能访问,并且需要完全登录状态才能访问,本次使用注解实现
public interface EmployeeService {
// @Secured("ROLE_HR")
//添加访问权限为全部登录以及是HR用户
@PreAuthorize("isFullyAuthenticated() && hasRole('HR')")
List findAll();
}
package cn.qblank.service.impl;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Service;
import cn.qblank.entity.Employee;
import cn.qblank.service.EmployeeService;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Override
public List findAll() {
//使用集合模拟集合
return Arrays.asList(
new Employee(1, "张三", "男"),
new Employee(2,"李四","女"),
new Employee(3,"王五","男"));
}
}
上文说到完全登录才能进入该页面,表示通过登录页面进入该页面的称为完全登录,而通过Cookie记住密码,直接进入的叫不完全登陆状态。
接下来我们来测试一下:
清除session,再次输入admin/employee进入登录界面,这次我们勾选记住密码的复选框。
在这里我们需要实现记住密码的功能:
在记住密码中设置name="remember-me"
在WebSecurityConfig中开启注解并加上记住密码的配置,并注入remember-me的支持UserDetailService
开启注解
//开启web security支持:应用bean容器里的WebSecurityConfigurer
@EnableGlobalMethodSecurity(securedEnabled = true,
//开启注解
prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
注入UserDetailService
@Autowired
private UserDetailsService userDetailsService;
/**
* 给用户、静态资源进行权限管理
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll() //给login的访问权
.antMatchers("/assets/**").permitAll() //给静态文件的访问权
.antMatchers("/admin/**").hasRole("ADMIN") //设置admin路径下的文件只能admin访问
.antMatchers("/**").authenticated().and() //给管理员普通赋予普通资源的权限
.formLogin() //用于表单
.loginPage("/login") //自定义表单提交页面
.and()
//添加记住功能
.rememberMe()
//开启remember Me的支持
.userDetailsService(userDetailsService)
//记住八小时
.tokenValiditySeconds(8*3600);
}
接下来我们重启浏览器
我们可以看到即使有记住密码也需要登陆,这就是不完全登陆
我们还可以使用SpringSecurity进行对不同用户访问的同样界面进行控制
这时我们可以使用Spring-security中的jsp标签库
1.首先导入jar包
2.在jsp中的引入标签库
<%@taglib uri="http://www.springframework.org/security/tags" prefix="ss" %>
员工表
使用admin用户登陆
使用hr用户登陆
完整项目路径: https://github.com/qblank/SpringSecurity