一、什么是springsecurity?
spring security 是用于spring里提供的一个安全框架,提供认证和授权功能,简单的说,就是作一个权限控制。作为一个入门新手,简单总结一下自己在spring security中的学习。
二、spring框架下springsecurity的用法
常规而言,ssm搭配是Shiro,但是由于此次项目学习的是ssm框架中使用spring security.
1、导入依赖
<properties>
<spring.security.version>5.0.1.RELEASE</spring.security.version>
</properties>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
2、在web.xml中创建filter
<!-- 配置类加载类路径的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:conf/spring-security.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置filter-->
<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>
注意: filter-name标签元素中名字“springSecurityFilterChain”不能写错,也不能修改,这个是固定的。
3、spring security 核心文件配置(spring-security.xml)
<?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">
<!-- 配置不拦截的资源 -->
<security:http pattern="/login.jsp" security="none"/>
<security:http pattern="/failer.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 auto-config="true" use-expressions="false">
<!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER的角色" -->
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>
<!-- 定义跳转的具体的页面 -->
<security:form-login
login-page="/login.jsp"
default-target-url="/index.jsp"
authentication-failure-url="/failer.jsp"
authentication-success-forward-url="/pages/main.jsp"
/>
<!-- 关闭跨域请求 -->
<security:csrf disabled="true"/>
<!-- 退出 -->
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" />
</security:http>
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式-->
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置加密类 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
</beans>
这个是结合数据库中使用spring security,这里面要注意加密方式。BCrptPasswordEncoder是spring security里的一种比较好的加密方式,可以非常方便的实现密码的加密加盐,相同明文加密出来的结果总是不同,这样就不需要用户去额外保存盐的字段了,这一点比 Shiro 要方便很多。
通过以上步骤,我们已经基本配置好了spring security。
那么在项目中是如何应用的呢?
我们首相分析一下文中的配置,在调用登入页面login.jsp,这个页面在配置不拦截资源里,所以在调用时不会被拦截,肯定是要能够正常访问到。还有就是失败页面,也不会设置成被拦截。
4、后端代码层分析
①用户输入账号密码、点击登入
此时,<security:authentication-provider user-service-ref=“userService”>里的userService会去寻找到后台中对应的userService对象,如下代码所示。因为其父类接口IUserService集成了UserDetailsService,所以重写了loadUserByUsername方法。找到userService后调用其loadUserByUsername方法进行账号密码验证。此外还有就是权限的验证。
@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = userDao.findByUsername(username);
}catch (Exception e){
e.printStackTrace();
}
//System.out.println("<<<<<"+userInfo.toString());
//处理自己的用户对象封装成UserDetails
User user = new User(userInfo.getUsername(),userInfo.getPassword(),userInfo.getStatus()==0?false:true,true,true,true,getAuthorities(userInfo.getRoles()));
//System.out.println(">>>>"+user.toString()+user.getPassword());
return user;
}
//对认证主题的应用层面的授权,含当前用户的权限信息
private List<SimpleGrantedAuthority> getAuthorities(List<Role> roles){
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
for(Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
}
return authorities;
}
}
②用户登入失败和成功跳转
当用户登入失败,即账号密码错误或者权限不足时,会跳转到我们设置好的authentication-failure-url="/failer.jsp"中的failer.jsp页面。成功则是进入我们设置好的main.jsp主页面。
③新建用户后端的密码设置问题
由于我们使用的是BCryptPasswordEncoder加密方式进行验证,那么,在我们新建用户时,保存用户密码也须先对用户密码进行密码编码。在此贴一下新建用户密码的service层代码:
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public int save(UserInfo userInfo) throws Exception {
//创建一个UUID
userInfo.setId(CreateUUIDUtils.createID());
//给密码加密
userInfo.setPassword(bCryptPasswordEncoder.encode(userInfo.getPassword()));
return userDao.save(userInfo);
}
这里的UUID是由于使用的是mysql数据库,自增主键ID没有想oracle里可以自动设置为UUID格式。
上面可以看到,给密码加密使用是BCryptPasswordEncoder中的encode方法。保证用户登入时传入的密码和数据库中获取的密码是一致的。