SpringSecurity
給用戶添加真正的角色
在UserDao中的findByUsername方法,增加查詢roleList
/**
* 根據用戶名查詢用戶對象(唯一)
* @param username
* @return
*/
@Select("select * from sys_user where username = #{username} and status = 1")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "roleList", column = "id", javaType = List.class,
//根據userId查詢角色列表findRoleListByUserId
many = @Many(select = "com.itheima.dao.RoleDao.findRoleListByUserId", fetchType = FetchType.LAZY))
})
SysUser findByUsername(String username);
給用戶添加上真正的角色
/**
* 通過用戶名得到用戶對象
* 創建用戶詳情對象,返回
* @param username
* @return UserDetails:用戶詳情
* @throws UsernameNotFoundException
*/
@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);
Collection<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : sysUser.getRoleList()) {
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+role.getRoleName());
authorities.add(grantedAuthority);
}
/**
* 參數1:username
* 參數2:password
* 參數3:角色列表對象
*/
UserDetails user = new User(sysUser.getUsername(),sysUser.getPassword(),authorities);
return user;
}
return null;
}
修改spring-security.xml
<security:http auto-config="true" use-expressions="true">
<!-- 配置攔截的請求地址,任何請求地址都必須有ROLE_ADMIN,ROLE_USER的權限 -->
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMIN','ROLE_USER')"/>
<!--指定安全框架使用的頁面-->
<!--
login-page:指定登錄頁面
login-processing-url:登錄的請求路徑,登錄時必須使用該路徑
default-target-url:登錄成功後進入的頁面
authentication-failure-url:認證失敗要進入的頁面
-->
<security:form-login login-page="/login.jsp"
login-processing-url="/login"
default-target-url="/index.jsp"
authentication-failure-url="/login.jsp"
></security:form-login>
<!--關閉跨站請求僞造-->
<security:csrf disabled="true"></security:csrf>
<!-- 退出 -->
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp"/>
<!--如果訪問被拒絕,則跳轉失敗頁面-->
<security:access-denied-handler error-page="/failer.jsp"></security:access-denied-handler>
</security:http>
控制前端頁面
- 引入security標籤庫
<security:authorize access="hasRole('ROLE_ADMIN')">
將需要管理員身份的部分括起來
<%@ page language="java" isELIgnored="false" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="${pageContext.request.contextPath}/img/user2-160x160.jpg"
class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>
<security:authentication property="principal.username" />
</p>
<a href="#"><i class="fa fa-circle text-success"></i> 在線</a>
</div>
</div>
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu">
<li class="header">菜單</li>
<li id="admin-index"><a
href="${pageContext.request.contextPath}/pages/main.jsp"><i
class="fa fa-dashboard"></i> <span>首頁</span></a></li>
<security:authorize access="hasRole('ROLE_ADMIN')">
<li class="treeview"><a href="#"> <i class="fa fa-cogs"></i>
<span>系統管理</span> <span class="pull-right-container"> <i
class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li id="system-setting"><a
href="${pageContext.request.contextPath}/user/findAll"> <i
class="fa fa-circle-o"></i> 用戶管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/role/findAll"> <i
class="fa fa-circle-o"></i> 角色管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/permission/findAll">
<i class="fa fa-circle-o"></i> 權限管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/pages/syslog-list.jsp"> <i
class="fa fa-circle-o"></i> 訪問日誌
</a></li>
</ul></li>
</security:authorize>
<li class="treeview"><a href="#"> <i class="fa fa-cube"></i>
<span>基礎數據</span> <span class="pull-right-container"> <i
class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li id="system-setting"><a
href="${pageContext.request.contextPath}/product/findAll">
<i class="fa fa-circle-o"></i> 產品管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/order/findAll">
<i class="fa fa-circle-o"></i> 訂單管理
</a></li>
</ul></li>
</ul>
</section>
<!-- /.sidebar -->
</aside>
此時只有用戶權限的用戶將只會看到基礎數據部分
但服務器端沒有被控制,當訪問路徑正確時,還是能訪問到被管理員控制的部分
控制服務端
一、在spring-mvc.xml中添加註解
- 開啓aop的自動代理(這句話加不加好像都能用,但加上這句話,下面這句就能寫在spring-security.xml中,否則不行)
- 配置security的註解支持(主要加這句話)
<!--開啓aop的自動代理-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<!--配置security的註解支持-->
<security:global-method-security secured-annotations="enabled"></security:global-method-security>
二、給只能被管理員訪問的模塊上加上
@Secured({"ROLE_ADMIN"})
@Secured({"ROLE_ADMIN"})
public class UserController
@Secured({"ROLE_ADMIN"})
public class RoleController
@Secured({"ROLE_ADMIN"})
public class PermissionController
aop管理日誌
創建日誌表和實體類
create sequence log_seq;
CREATE TABLE sys_log(
id number PRIMARY KEY,
visitTime DATE,
username VARCHAR2(50),
ip VARCHAR2(30),
method VARCHAR2(200)
)
public class SysLog {
private Long id;
//訪問時間
private Date visitTime;
//訪問的用戶名
private String username;
//訪問的ip地址
private String ip;
//訪問的全限類名.方法
private String method;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getVisitTime() {
return visitTime;
}
public void setVisitTime(Date visitTime) {
this.visitTime = visitTime;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
LogController
掃描log包,創建對象
<context:component-scan base-package="com.itheima.log"></context:component-scan>
配置切面
注意:如果不用springmvc如何得到request對象?
配置請求監聽器,當請求發生時,在容器中創建請求對象
<!--配置請求監聽器,當請求發生時,在容器中創建請求對象-->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
/**
* 註解配置AOP
* 提供一個類,配置爲切面類
* 切面:切入點+通知
* 通知:
* 1.前置增強:@Before
* 2.後置增強: @AfterReturning
* 3.最終增強:@After
* 4.異常增強:@AfterThrowing
* 5.環繞增強:@Around
*
*
*/
@Component
@Aspect
public class LogController {
@Autowired
LogService logService;
@Autowired
HttpServletRequest request;
/**
* 切入點
*/
@Pointcut("execution(* com.itheima.controller.*.*(..))")
public void pointcut(){}
/**
* 織入
* 環繞增強
* ProceedingJoinPoint:連接點對象,可以執行真實對象的真實方法,只在環繞增強中使用
* JoinPoint:連接點對象,不可以執行真實對象的真實方法
*/
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint){
//創建日誌對象
SysLog log = new SysLog();
//將日誌對象封裝
//1. 訪問時間
log.setVisitTime(new Date());
//2. 訪問用戶名,從安全框架得到
//獲取securityContext對象
SecurityContext context = SecurityContextHolder.getContext();
//獲取認證對象
Authentication authentication = context.getAuthentication();
//獲取用戶對象
User user = (User)authentication.getPrincipal();
//獲取用戶名
String username = user.getUsername();
log.setUsername(username);
//3. 訪問的ip地址,從請求對象獲得
//getRemoteAddr()獲取ip地址
String ip = request.getRemoteAddr();
log.setIp(ip);
//4. 訪問的全限類名.方法
//得到被攔截的對象
Object target = joinPoint.getTarget();
//獲取被攔截的類的全限類名
String className = target.getClass().getName();
//獲取被攔截的方法
Signature signature = joinPoint.getSignature();
//獲取方法名
String methodName = signature.getName();
//將日誌對象存儲到數據庫中
log.setMethod(className+"."+methodName);
//System.out.println(log);
logService.save(log);
try {
//執行真實的方法,需要把真實方法的返回值返回,如果不返回,所有方法被攔截,沒有執行返回值
return joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
LogService
@Service
public class LogServiceImpl implements LogService {
@Autowired
LogDao logDao;
@Override
public void save(SysLog log) {
logDao.save(log);
}
}
LogDao
public interface LogDao {
/**
* 保存日誌
* @param log
*/
@Insert("insert into sys_log values(log_seq.nextval,#{visitTime},#{username},#{ip},#{method})")
void save(SysLog log);
}