企業級權限管理項目(六)
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>