企业级权限管理项目(六)
SpringSecurity
在服务端获取用户名
当用户通过安全框架进行登录后,如何在服务端获取该用户的用户名?从session域中获取登录信息
方法一:
- 创建ShowUsernameController,获取session对象
HttpSession session = request.getSession();
- 从session对象中获取所有的属性名
Enumeration attributeNames = session.getAttributeNames();
- 遍历枚举类型,通过打印结果,得知存储在session中的属性名。获取到
SPRING_SECURITY_CONTEXT
:存储用户登录信息的session中的名称
//hasMoreElements()判断是否有更多的元素
//nextElement()获取枚举中的下一个元素
while (attributeNames.hasMoreElements()){
System.out.println(attributeNames.nextElement());
}
- 获取安全框架的上下文对象,
SecurityContext
对象
SecurityContext securityContext = (SecurityContext)spring_security_context;
- 获取认证信息
Authentication authentication = securityContext.getAuthentication();
- 获取用户详情信息(
UserDetails
对象)
//获取重要信息,就是用户详情对象(UserDetails)
Object principal = authentication.getPrincipal();
User user = (User) principal;
- 获取用户名
//获取用户名
String username = user.getUsername();
System.out.println(username);
方法二:
直接获得安全框架的上下文对象,然后按照上面步骤进行。此上下文对象和上述对象相同
SecurityContext context = SecurityContextHolder.getContext();
在页面中显示用户名
方法一:EL表达式,可以和上述步骤进行对应
${sessionScope.SPRING_SECURITY_CONTEXT.authentication.principal.username}
方法二:security标签库,首先引入security的标签库
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<security:authentication property="principal.username" />
退出操作
点击注销之后,清空session,并跳转login页面
之前已经配置过了
<!-- 退出 -->
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp"/>
</security:http>
所以直接修改访问路径即可
<div class="pull-right">
<a href="${pageContext.request.contextPath}/logout"
class="btn btn-default btn-flat">注销</a>
</div>
用户模块
查询所有用户
UserController
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/findAll")
public ModelAndView findAll(){
//查询数据
List<SysUser> userList = userService.findAll();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("userList",userList);
modelAndView.setViewName("user-list");
return modelAndView;
}
}
UserService
@Override
public List<SysUser> findAll() {
return userDao.findAll();
}
UserDao
/**
* 查询全部用户
* @return
*/
@Select("select * from sys_user")
List<SysUser> findAll();
前端
<tbody>
<c:forEach items="${userList}" var="user">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${user.id }</td>
<td>${user.username }</td>
<td>${user.email }</td>
<td>${user.phoneNum }</td>
<td>${user.status==1?"激活":"未激活" }</td>
<td class="text-center">
<a href="${pageContext.request.contextPath}/pages/user-show.jsp" class="btn bg-olive btn-xs">详情</a>
<a href="${pageContext.request.contextPath}/pages/user-role-add.jsp" class="btn bg-olive btn-xs">添加角色</a>
</td>
</tr>
</c:forEach>
</tbody>
添加用户
UserController
/**
* 保存用户
* @param user
* @return
*/
@RequestMapping("/save")
public String save(SysUser user){
userService.save(user);
return "redirect:/user/findAll";
}
UserService
@Override
public void save(SysUser user) {
userDao.save(user);
}
UserDao
/**
* 保存用户
* @param user
*/
@Insert("insert into sys_user values(user_seq.nextval,#{username},#{email},#{password},#{phoneNum},#{status})")
void save(SysUser user);
md5密码加密
md5加密工具类
package com.itheima.utils;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
/**
* 使用md5的算法进行加密
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
public static void main(String[] args) {
System.out.println(md5("123"));
}
}
添加用户方法加密
@Override
public void save(SysUser user) {
//获取明文密码
String password = user.getPassword();
//对明文密码进行加密
String md5Password = MD5Utils.md5(password);
//把加密后的密码存储到user对象中
user.setPassword(md5Password);
userDao.save(user);
}
当输入密码为123时,就会进行加密操作
但会出现一个问题,相同的密码加密后的密文相同
SpringSecurity密码加密
在md5的基础上,把一个随机数作为密钥生成密文
一、在spring-security.xml中添加配置,创建加密工具类对象
<!--创建加密工具类对象-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
二、自动注入
@Autowired
PasswordEncoder passwordEncoder;
三、加密
@Override
public void save(SysUser user) {
//获取明文密码
String password = user.getPassword();
//对明文密码进行加密
String securityPassword = passwordEncoder.encode(password);
//把加密后的密码存储到user对象中
user.setPassword(securityPassword);
userDao.save(user);
}
SpringSecurity登录细节实现
虽然进行了加密,但加密后的密码无法使用原密码登录,所以登录还要细节没有完成
一、在spring-security.xml中添加一句
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
添加之后
<!-- 配置认证(登录)信息:认证管理器 -->
<security:authentication-manager>
<!--认证信息的提供者:关联用户服务对象,提供账号和密码-->
<security:authentication-provider user-service-ref="userServiceImpl">
<!--指定加密工具类-->
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
<!--<!–用户服务对象–>
<security:user-service>
<!–用户信息:临时的账号和密码
{noop}:不使用加密
authorities:指定用户的认证角色
–>
<security:user name="admin" password="{noop}admin" authorities="ROLE_USER"/>
</security:user-service>-->
</security:authentication-provider>
</security:authentication-manager>
二、将UserDetails中的{noop}
去除
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名获取用户(SysUser)对象
SysUser sysUser = userDao.findByUsername(username);
System.out.println(username);
System.out.println(sysUser);
if(sysUser!=null){
//创建角色集合对象
Collection<GrantedAuthority> authorities = new ArrayList<>();
//创建临时角色对象
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
//对象添加到集合中
authorities.add(grantedAuthority);
/**
* 参数1:username
* 参数2:password
* 参数3:角色列表对象
*/
UserDetails user = new User(sysUser.getUsername(),sysUser.getPassword(),authorities);
return user;
}
return null;
}
注意细节:先配置认证信息,再创建加密工具类
解析标签security:authentication-provider,判断该标签中是否存在子标签security:password-encoder‘
- 如果有此子标签,则使用指定密码加密工具类
- 如果没有此子标签,则从spring容器中查询名称为passwordEncoder,的加密工具类,使用从容器中获取的工具类
<!-- 配置认证(登录)信息: 认证管理器 -->
<security:authentication-manager>
<!--认证信息的提供者: 关联用户服务对象-提供账号和密码-->
<!--
解析标签security:authentication-provider,判断该标签中是否存在子标签security:password-encoder‘
如果有此子标签,则使用指定密码加密工具类
如果没有此子标签,则从spring容器中查询名称为passwordEncoder,的加密工具类,使用从容器中获取的工具类
-->
<security:authentication-provider user-service-ref="userService">
<!--指定登录加密工具类-->
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
<!--用户的服务对象-->
<!--<security:user-service>-->
<!--用户信息:是临时账号和密码-->
<!--{noop}: 不使用加密-->
<!--authorities: 指定用户的认证角色-->
<!--<security:user name="admin" password="{noop}admin" authorities="ROLE_USER"/>-->
<!--</security:user-service>-->
</security:authentication-provider>
</security:authentication-manager>
<!--创建一个加密工具类-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>