本文章将介绍Spring Security更多基本用法,不断迭代成为实际项目中可用的技术。文章目前针对于spring,与spring boot整合将在以后出文章。
一.创键一个页面,设置为可以匿名访问
匿名访问:即不管该用户是否有没有认证或授权,都可以访问
a.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
可以匿名访问
</body>
</html>
在spring-security配置文件中加入:(不知道这里配置文件的请到第一篇文章查看明细 Spring Security 快速入门(1))
<!-- 配置可以匿名访问的标签-->
<security:http security="none" pattern="/pages/a.html"></security:http>
进行访问a.html,发现并没有进入登录界面,表示a.html是可以匿名访问的
二.将Spring Security的默认登录页面改为我们自己设定的login界面
编写一个登陆界面 mylogin.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h3>自定义登录页面</h3>
<form action="/mylogin.do" method="post">
username:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
登录界面需要每个用户都可以进行访问,即匿名访问,所以进行配置文件改写:
<security:http security="none" pattern="/mylogin.html"></security:http>
另外我们还要将通过配置文件将Spring Security的默认登录页面改为我们自定义的页面:
注释:
login-page: 设定登陆界面
username-parameter:设置用户名对应mylogin.html中的哪个参数
password-parameter:设置用密码对应mylogin.html中的哪个参数login-processing-url:登录提交到后台的请求地址
default-target-url:登陆成功跳转到的页面
authentication-failure-url:登录失败跳转到的页面csrf:对应CsrfFilter过滤器
disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403)
<security:http auto-config="true" use-expressions="true">
<security:form-login
login-page="mylogin.html"
username-parameter="username"
password-parameter="password"
login-processing-url="/mylogin.do"
default-target-url="index.html"
authentication-failure-url="mylogin.html"
></security:form-login>
<security:csrf disabled="true"></security:csrf>
</security:http>
这样设置后,我们就可以成功调整转到我们自己定义的页面啦
三.通过数据库验证用户密码、权限等
首先需要创建一个类,该类继承框架提供UserDetailsService接口,用于实现数据库相关逻辑:
public class SpringSecurityUserService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
上面重写方法中username是在我们login登录界面获取的username,我们需要做的就是根据用户名从用户表中查询该用户,获得还用户的密码和权限
另外还有一个返回的userDetails,它有一个实现类User:
//username 用户的username
//password 用户登录的密码(如果为明文,则在前面加上 {noop} )
// authorities 该用户被授予的权限
public User(String username, String password,
Collection<? extends GrantedAuthority> authorities) {
this(username, password, true, true, true, true, authorities);
}
下面是loadUserByUsername的基本内容:
public class SpringSecurityUserService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//从数据库中根据用户名查找实体对象
Student student=StudentDao.findByUsername(username);
if(studen==null){
return null; // 如果该用户没查到,则表示没有该用户的信息,直接登陆不成功
}
ArrayList<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("permission_A")); //授予权限
grantedAuthorities.add(new SimpleGrantedAuthority("permission_B"));
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); //授予角色
return new User(username,"{noop}"+student.getPassword(),grantedAuthorities); //密码使用明文
}
}
四.对于密码加密后怎么设置
前面我们使用的密码都是明文的,这是非常不安全的。一般情况下用户的密码需要进行加密后再保存到数据库中。
常见的密码加密方式有:
3DES、AES、DES:使用对称加密算法,可以通过解密来还原出原始密码
MD5、SHA1:使用单向HASH算法,无法通过计算还原出原始密码,但是可以建立彩虹表进行查表破解
bcrypt:将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题
加密后的格式一般为:
$2a 10 10 10/bTVvqqlH9UiE0ZJZ7N2Me3RIgUCdgMheyTgV0B4cMCSokPa.6oCa
第一步:在spring-security.xml文件中指定密码加密对象
<security:authentication-manager>
<security:authentication-provider user-service-ref="springSecurityUserService">
<security:password-encoder ref="bCryptPasswordEncoder"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="springSecurityUserService" class="com.zj.service.SpringSecurityUserService"></bean>
<bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
第二部:修改SpringSecurityUserService
当然使用bcrypt,要求数据库保存密码数据时也要使用bcrypt
在SpringSecurityUserService返回对象时,不需要{noop} 了,会自动启用我们配置的加密规则
return new User(username,student.getPassword(),grantedAuthorities);
五.配置多种校验规则(xml)
<!--只要认证通过就可以访问-->
<security:intercept-url pattern="/index.jsp" access="isAuthenticated()" /> <security:intercept-url pattern="/a.html" access="isAuthenticated()" />
<!--拥有add权限就可以访问b.html页面-->
<security:intercept-url pattern="/b.html" access="hasAuthority('add')" />
<!--拥有ROLE_ADMIN角色就可以访问c.html页面-->
<security:intercept-url pattern="/c.html" access="hasRole('ROLE_ADMIN')" />
<!--拥有ROLE_ADMIN角色就可以访问d.html页面, 注意:此处虽然写的是ADMIN角色,框架会自动加上前缀ROLE_-->
<security:intercept-url pattern="/d.html" access="hasRole('ADMIN')" />
六.注解模式开发():
可以替换 security:intercept-url pattern="/b.html" access=“hasAuthority(‘add’)” />的简化配置
主要用在Controller层的方法上
需要在spring-security中配置注解扫描
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.zj.Controller.StudentController"></context:component-scan>
<security:global-method-security></security:global-method-security> //开启security的注解方式
@RequestMapping("/add")
@PreAuthorize("hasAuthority('ROLE_ADMIN')") // 表示必须有ROLE_DAMIN角色才可以访问此方法,否则抛出403
public void add(@RequestBodyStudent student){
}
六.Security退出登录(放在security:http标签里面)
logout-url:退出登录操作对应的请求路径
logout-success-url:退出登录后的跳转页面 -->
<security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>
当访问/logout.do 即会触发退出登录,退出成功后将跳转到页面login.html