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);
}