Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解
决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了
Spring IoC,DI(控制反转 Inversion of Control ,DI:Dependency Injection 依赖注入)和 AOP(面
向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控
制编写大量重复代码的工作。
在spring依赖引入的基础上,引入spring Security依赖,版本可以使用spring的版本
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-configartifactId>
dependency>
1)添加加载Security配置的监听器,
2)注册安全认证的过滤器链
这些过滤器实际是在spring容器中管理,这里只是代理注册给web容器
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring/spring-security.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<filter>
<filter-name>springSecurityFilterChainfilter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSecurityFilterChainfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
使用静态用户(死数据)
<bean:beans xmlns="http://www.springframework.org/schema/security"
xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.1.xsd">
<http pattern="/login.html" security="none">http>
<http pattern="/loginerror.html" security="none">http>
<http pattern="/css/**" security="none">http>
<http pattern="/img/**" security="none">http>
<http pattern="/js/**" security="none">http>
<http pattern="/plugins/**" security="none">http>
<http>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login.html"
login-processing-url="/login"
always-use-default-target="true"
default-target-url="/admin/index.html"
authentication-failure-url="/loginerror.html"
/>
<logout logout-url="/logout" logout-success-url="/login.html"/>
<csrf disabled="true" />
<headers>
<frame-options policy="SAMEORIGIN" />
headers>
http>
<authentication-manager>
<authentication-provider>
<user-service>
<user authorities="ROLE_USER" name="admin" password="123456" />
user-service>
authentication-provider>
authentication-manager>
bean:beans>
错误一、未关闭跨域请求,csrf disabled=”true” 关闭 csrf ,如果不加会出现错误
错误二,未放行登录页面,如果你没有设置登录页 security=”none” ,将会出现以下错误
简单的登录页面
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登陆title>
head>
<body>
<form action='/login' method='POST'>
<table>
<tr>
<td>用户名:td>
<td><input type='text' name='username' value=''>td>
tr>
<tr>
<td>密码:td>
<td><input type='password' name='password' />td>
tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value=" 登陆 " />td>
tr>
table>
form>
body>
html>
用户认证类
package com.it.manager.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.it.manager.service.SellerService;
import com.it.pojo.TbSeller;
public class userDetailServiceImpl implements UserDetailsService {
private SellerService sellerService;
public SellerService getSellerService() {
return sellerService;
}
public void setSellerService(SellerService sellerService) {
this.sellerService = sellerService;
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List grantedAuths = new ArrayList();
//这里设置一个默认权限,也可以通过数据库查询出用户访问权限进行设置
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
// 调用sellerService查询用户
TbSeller seller = sellerService.findOne(username);
if (seller != null && seller.getPassword() != null) {
//查询返回一个Security框架规定的用户对象,并将用户帐号,密码及权限信息以构造方式传入
return new User(username, seller.getPassword(), grantedAuths);
} else {
return null;
}
}
}
在SpringSecurity.xml中设置:
1)注册自定义认证类,并注入到认证管理器中
2)设置加密方式
BCrypt 加密算法
用户表的密码通常使用 MD5 等不可逆算法加密后存储,为防止彩虹表破解更会先使用
一个特定的字符串(如域名)加密,然后再使用一个随机的 salt(盐值)加密。 特定字符
串是程序代码中固定的,salt 是每个密码单独随机,一般给用户表加一个字段单独存储,比
较麻烦。 BCrypt 算法将 salt 随机并混入最终加密后的密码,验证时也无需单独提供之前的
salt,从而无需单独处理 salt 问题。
<bean:beans xmlns="http://www.springframework.org/schema/security"
xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.1.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<http pattern="/login.html" security="none">http>
<http pattern="/loginerror.html" security="none">http>
<http pattern="/css/**" security="none">http>
<http pattern="/img/**" security="none">http>
<http pattern="/js/**" security="none">http>
<http pattern="/plugins/**" security="none">http>
<http pattern="/seller/insert" security="none">http>
<http pattern="/shoplogin.html" security="none">http>
<http pattern="/register.html" security="none">http>
<http>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login
login-page="/shoplogin.html"
login-processing-url="/login"
always-use-default-target="true"
default-target-url="/admin/index.html"
authentication-failure-url="/loginerror.html" />
<logout logout-url="/logout" logout-success-url="/login.html" />
<csrf disabled="true" />
<headers>
<frame-options policy="SAMEORIGIN" />
headers>
http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref='userDetailService'>
<password-encoder ref="bcryptEncoder">password-encoder>
authentication-provider>
authentication-manager>
<bean:bean id="bcryptEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<dubbo:application name="shop-web-2" />
<dubbo:registry address="zookeeper://192.168.11.11:2181" />
<dubbo:reference id="sellerService"
interface="com.it.manager.service.SellerService">
dubbo:reference>
<dubbo:annotation package="com.it.shop.controller" />
<bean:bean id="userDetailService" class="com.it.manager.service.userDetailServiceImpl">
<bean:property name="sellerService" ref="sellerService">
bean:property>
bean:bean>
bean:beans>
@RequestMapping("/register")
public Result add(UserEntity userEntity){
//密码加密
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode(userEntity.getPassword());
userEntity.setPassword(password);
try {
UserService.register(userEntity);
return new Result(true, "增加成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "增加失败");
}
}
在业务层方法上通过注解@PreAuthorize,配置调用方法需要的权限:
例如:@PreAuthorize(“hasAuthority(‘PRODUCT_LIST’)”)
/**
*
* 查询所有商品
* @PreAuthorize("hasAuthority('PRODUCT_LIST')")
* 配置调用该业务层方法需要的权限为:PRODUCT_LIST
* 该注解为,在调用业务方法之前验证权限
* */
@PreAuthorize("hasAuthority('PRODUCT_LIST')")
@Transactional(propagation = Propagation.SUPPORTS ,readOnly = true)
public PageInfo findAllProduct(Integer pageNum,Integer pageSize){
PageHelper.startPage(pageNum, pageSize);
List products = productDao.findAllProduct();
PageInfo pageInfo = new PageInfo(products);
return pageInfo;
};