SpringScurity的快速入门
什么是SpringScurity
springScurity是为基于spring的应用程序提供安全保护的声明示安全框架,它可以在处理web请求的时候通过过滤器链对类和方法进行认证([authentication)和授权(authorization);
SpringScurity的XML配置
1.导入SpringScurity的相关jar包
2.在web.XML里面配置如下代码:
<!-- 配置加载类路径的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml,classpath*:spring-security.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.创建一个springScurity的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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.xsd">
<!--配置权限颗粒器-->
<!--@Secured注解支持 : secured-annotations="enabled"-->
<!--@RolesAllowed注解支持 : jsr250-annotations--> 需要添加jsr250 jar包
<!--开启全局方法安全控制-->
<security:global-method-security secured-annotations="enabled" jsr250-annotations="enabled" pre-post-annotations="enabled"/>
<!--配置不拦截的资源-->
<security:http pattern="/failer.jsp" security="none"/>
<security:http pattern="/login.jsp" security="none"/>
<security:http pattern="/css/**" security="none"/>
<security:http pattern="/img/**" security="none"/>
<security:http pattern="/plugins/**" security="none"/>
<!--
配置具体的规则
auto-config="true" 不用自己编写登录的页面,框架提供默认登录页面
use-expressions="false" 是否使用SPEL表达式(没学习过)
-->
<security:http use-expressions="true">
<!--配置具体拦截的url,pattern是拦截的url,access是访问被拦截的url需要的权限-->
<security:intercept-url pattern="/**" access="hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"/>
<!--定义跳转的具体页面-->
<!--
form-login是spring security命名空间配置登录相关信息的标签,它包含如下属性:
1. login-page 自定义登录页url,默认为/login
2. login-processing-url 登录请求拦截的url,也就是form表单提交时指定的action
3. default-target-url 默认登录成功后跳转的url
4. always-use-default-target 是否总是使用默认的登录成功后跳转url
5. authentication-failure-url 登录失败后跳转的url
6. username-parameter 用户名的请求字段 默认为userName
7. password-parameter 密码的请求字段 默认为password
8. authentication-success-handler-ref 指向一个AuthenticationSuccessHandler用于处理认证成功的请求,不能和default-target-url还有always-use-default-target同时使用
9. authentication-success-forward-url 用于authentication-failure-handler-ref
10. authentication-failure-handler-ref 指向一个AuthenticationFailureHandler用于处理失败的认证请求
11. authentication-failure-forward-url 用于authentication-failure-handler-ref
12. authentication-details-source-ref 指向一个AuthenticationDetailsSource,在认证过滤器中使用
-->
<security:form-login
login-page="/login.jsp"
login-processing-url="/login.do"
default-target-url="/pages/main.jsp"
always-use-default-target="true"
authentication-failure-url="/failer.jsp"
/>
<!--关闭跨域请求,不关闭就会拦截所有的访问,显示权限不够-->
<!--<security:csrf disabled="true"/>-->
<security:csrf disabled="true"/>
<!--退出-->
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp"/>
</security:http>
<!--切换成数据库中的用户名和密码-->
<security:authentication-manager>
<!--配置需要加密的service-->
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式 -->
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<!--或者将验证方式改为直接认证不查数据库
<security:authentication-manager>
<!--配置service-->
<security:authentication-provider>
<security:user-service>
<security:user username="admin" password="123" authorities="ROLE_ADMIN"/>
<!--如果是springScurity5.0以上的版本
<security:user username="admin" password="{noop}123" authorities="ROLE_ADMIN"/>
-->
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
这样就不用写用户类和实现类了,账号和密码就是自己在user标签里面配的,权限一定要是<security:intercept-url pattern="/**" access="hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"/>里面的任何一个。也不需要配置加密器了
-->
<!--配置密码加密器,在登陆的时候一定要用密文登陆,如果用明文就需要在密码前加"{noop}"拼接-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
</beans>
编写service类
1.自定义一个service接口实现UserDetailService(该接口是SpringScurity提供的),复写它的登入方法.原理是当登入页面输入账号密码的时候,过滤器会获取用户在页面输入的数据,然后该接口的实现类会通过用户的账号去查数据库,如果数据库查出的数据和过滤器获取的数据匹配成功,则会跳转到自己设置的认证成功页面,并且该用户拥有相应的权限,就会认证成功,登陆通过。
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.List;
public interface UserService extends UserDetailsService {
@Override
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
2.实现类
import org.springframework.beans.factory.annotation.Autowired;
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.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
//将该类加入spring容器管理
@Service("userService")
//开启注解事务
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//查询数据库将信息封装到自己的对象类userInfo中
UserInfo userInfo = userInfoMapper.findUserByUsername(username);
//获取用户的权限列表
List<SimpleGrantedAuthority> authority = getAuthority(userInfo.getRoles());
//User是SpringScurity提供的类
User user = new User(userInfo.getUsername(),userInfo.getPassword(), userInfo.getStatus() != 0,true,true,true,authority);
//返回数据之后SpringScurity会将数据库查询的信息与拦截器中的数据对比
return user;
}
public List<SimpleGrantedAuthority> getAuthority(List<Role> roles){
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
}
return authorities;
}
}
3.配置完之后,不管访问哪个路径,SpringScurity都会判断该用户是否登陆,如果没有登陆,就会跳转到登陆页面。