springsecurity用户授权以及页面控制、后台页面控制

第1章 用户授权

1.1 角色从数据库加载
1.1.1 修改自定义授权认证类

修改自定义认证类,代码如下:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    //通过账号查询用户信息
    SysUser sysUser = userDao.getByUserName(username);

    if(sysUser!=null){
        // 先设置假的权限
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        //获取用户角色
        List<SysRole> roles = sysUser.getRoles();

        for (SysRole role : roles) {
            // 传入角色
            authorities.add(new SimpleGrantedAuthority(role.getRoleName()));
        }

        // 创建用户,这和用户是springsecurity中的User
        //User user = new User(username, "{noop}"+sysUser.getPassword(), authorities) ;
        User user = new User(username, sysUser.getPassword(), authorities) ;
        return user;
    }
    return null;
}
1.1.2 修改UserDao

直接修改Dao,通过@Many调用com.itheima.dao.RoleDao.getByUserId查询用户的角色信息。

/***
 * 查询用户信息
 * @param name
 * @return
 */
@Select("select * from sys_user where username=#{username}")
@Results(
        //根据用户信息查询角色信息
        @Result(property ="roles",column = "id",
                many = @Many(select = "com.itheima.dao.RoleDao.getByUserId",
                        fetchType = FetchType.LAZY))
)
SysUser getByUserName(String name);
1.2 access属性的配置

access的值是一个字符串,其可以直接是一个权限的定义,也可以是一个表达式。常用的类型有简单的角色名称定义,多个名称之间用逗号分隔。

 <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>
 在上述配置中就表示secure路径下的所有URL请求都应当具有ROLE_USER或ROLE_ADMIN权限。当access的值是以“ROLE_”开头的则将会交由RoleVoter进行处理。

此外,其还可以是一个表达式

use-expressions="true" <security:intercept-url pattern="/secure/**"  access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>

或者是使用hasRole()表达式,然后中间以or连接

<security:intercept-url pattern="/secure/**" access="hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')"/>

匿名访问配置:IS_AUTHENTICATED_ANONYMOUSLY表示用户不需要登录就可以访问;

第2章 用户模块

2.1 获取用户名
2.1.1 Session信息分析

我们使用SpringSecurity实现对用户的访问拦截操作,如果用户没有登录,那么SpringSecurity会让用户进行登录,但是目前为止,我们还从未获取过登录用户信息,用户信息会存储到哪里呢?根据我们以往的开发经验,一般会将用户信息存入Session,我们可以在用户登录之后将Session输出。

修改main.jsp,在内容区域处添加session信息

<!-- 内容区域 -->
<div class="content-wrapper">
   ${sessionScope}
</div>
<!-- 内容区域 /-->

用z1用户登录,session信息如下:

{SPRING_SECURITY_CONTEXT=org.springframework.security.core.context.SecurityContextImpl@bbe395ff:
 Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@bbe395ff: 
 Principal: org.springframework.security.core.userdetails.User@ef7: Username: z1; Password: [PROTECTED]; 
 Enabled: true; 
 AccountNonExpired: true; 
 credentialsNonExpired: true; 
 AccountNonLocked: true; 
 Granted Authorities: ROLE_USER; 
 Credentials: [PROTECTED]; 
 Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffe9938: RemoteIpAddress: 0:0:0:0:0:0:0:1; 
 SessionId: BA5BC6E21D04DEDEA4A539AD6B1205F1; 
 Granted Authorities: ROLE_USER}

Session信息中有一个key叫SPRING_SECURITY_CONTEXT,它所对应的类是SecurityContextImpl,这个类是SecurityContext接口的实现类,它里面包含一个对象Authentication,这个接口的实现类是UsernamePasswordAuthenticationToken,这个类里有个对象Principal,而这个对象就是User,这个User也就是每次我们登录封装的用户信息对象,里面包含了用户名,用户密码和授权信息。

​按照这个分析,我们可以直接从session中在页面取出用户信息,取法如下:

<!-- 内容区域 -->
<div class="content-wrapper">
   ${sessionScope.SPRING_SECURITY_CONTEXT.authentication.principal.username}
</div>
2.1.2 SpringSecurity标签获取用户信息

SpringSecurity也提供了对应的标签来获取用户信息,不过我们得先导入对应的标签包。

在ssm-parent中引入

<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-taglibs</artifactId>
	<version>${spring.security.version}</version>
</dependency>

在ssm-web中引入

  <dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
  </dependency>

在页面引入(header.jsp)

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<security:authentication property="principal.username" />
2.1.3 服务器端后台对象封装的分析
  1. 对象的封装,认证通过后会返回User对象,该对象中包含用户名等信息。
  2. principal(主角)就是User对象。
  3. 框架会把principal封装到Authentication(认证)对象中
  4. Authentication对象会封装到SecurityContext(Security上下文对象)中
  5. 最后会把SecurityContext绑定到当前的线程中

后台获取用户信息代码:

/***
 * 先获取到SecurityContext对象
 */
SecurityContext securityContext = SecurityContextHolder.getContext();

//获取认证对象
Authentication authentication = securityContext.getAuthentication();

//获取用户登录信息
User user = (User) authentication.getPrincipal();
System.out.println(user.getUsername());
2.1 页面权限控制
2.1.1 开启SpELl表达式

这里需要先开启SpELl表达式,否则不能使用SpringSecurity页面对应的标签。

设置use-expressions="true",access修改:access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"

<security:http auto-config="true" use-expressions="true">
    <!-- 配置拦截的请求地址,任何请求地址都必须有ROLE_USER的权限 -->
    <security:intercept-url pattern="/index.jsp" access="ROLE_USER" />
    <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
    
	//略....
</security:http>
2.1.2 页面使用security:authorize
<security:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_USER')">
	<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/list"> <i
				class="fa fa-circle-o"></i> 用户管理
		</a></li>
		<li id="system-setting"><a
			href="${pageContext.request.contextPath}/role/list"> <i
				class="fa fa-circle-o"></i> 角色管理
		</a></li>
        <security:authorize access="hasAnyRole('ROLE_ADMIN')">
		<li id="system-setting"><a
			href="${pageContext.request.contextPath}/permisson/list">
				<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>
        </security:authorize>
	</ul></li>
</security:authorize>
2.2 在服务器端控制权限

通过上面的控制,我们发现一个问题,用户只是页面看不到菜单按钮,但让然能访问原来地址,我们需要做后台权限控制。这里提供了多种注解方式实现,我们着重讲讲其中3种注解实现方式。但无论哪种方式,都需要首先开启AOP支持,并且不能多种注解同时使用。修改SpringMVC配置文件如下:

<!--开启AOP-->
<aop:aspectj-autoproxy proxy-target-class="true" />
2.2.1 @RolesAllowed

使用该注解需要首先引入依赖:

在pom.xml中引入:

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>jsr250-api</artifactId>
    <version>1.0</version>
</dependency>

在spring-security.xml配置文件中开启JSR-250的注解支持

<security:global-method-security jsr250-annotations="enabled"/>

在Controller的类或者方法上添加注解

@RolesAllowed("ROLE_ADMIN")
public class RoleController {}
2.2.2 security注解方式权限拦截:@Secured

在spring-security.xml配置文件中开启注解支持

<security:global-method-security secured-annotations="enabled"/>

在Controller类或者方法添加注解

@Secured("ROLE_ADMIN")
public class RoleController{}
2.2.3 Spring表达式的方式

在spring-security.xml配置文件中开启注解支持

<security:global-method-security pre-post-annotations="enabled"/>

在Controller类或者方法添加注解

@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public class RoleController {}
2.3 页面403处理

在用户没有权限访问时,经常会出现403页面,不是很友好。SpringSecurity对这个也有控制,只需要在spring-security.xml中加上如下配置即可。

<security:access-denied-handler error-page="/403.jsp"/>

1542953715840

第3章 日志功能

3.1 搭建日志开发环境

创建日志表结构

--日志表
CREATE TABLE `sys_log` (
  `id` int(10) NOT NULL,
  `visitTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `username` varchar(50) DEFAULT NULL,
  `ip` varchar(30) DEFAULT NULL,
  `method` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

同时为表结构创建SysLog实体Bean

public class SysLog {
    private Long id;
    private Date visitTime;
    private String username;
    private String ip;
    private String method;
	//get...set...
}

创建SysLogDao接口

public interface SysLogDao {
    /**
     * 增加日志
     * @param sysLog
     */
    @Insert("insert into sys_log(visitTime,username,ip,method)values(#{visitTime},#{username},#{ip},#{method})")
    void addLog(SysLog sysLog);

}

创建SysLogService接口

public interface SysLogService {
    void addLog(SysLog sysLog);
}

创建SysLogServiceImpl实现类

@Service
public class SysLogServiceImpl implements SysLogService {

    @Autowired
    private SysLogDao sysLogDao;

    @Override
    public void addLog(SysLog sysLog) {
        sysLogDao.addLog(sysLog);
    }
}
3.2 AOP日志操作类

由于需要记录用户IP,所以需要创建RequestContextListener监听,它会把每次用户请求注入到SpringIOC容器中。

在web.xml中添加监听器

<!-- 配置监听器,监听request域对象的创建和销毁的 -->
<listener>
	<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

创建LogHandler类

@Aspect
@Component
public class LoggerHandler {

    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private HttpServletRequest request;

    /***
     * 前置通知日志操作
     * @param jp
     */
    @Before(value = "execution(* com.itheima.controller.*Controller.*(..))")
    public void logBefore(JoinPoint jp){
        addLog(jp,"Before");
    }

    /***
     * 后置通知日志操作
     * @param jp
     */
    @After(value = "execution(* com.itheima.controller.*Controller.*(..))")
    public void logAfter(JoinPoint jp){
        addLog(jp,"After");
    }

    /***
     * 添加日志
     * @param jp
     */
    public void addLog(JoinPoint jp,String adviceType){
        //获取用户的IP
        String ip = request.getRemoteAddr();
        //方法名字
        String methodName = jp.getSignature().getName();
        Class clazz = jp.getSignature().getDeclaringType();

        SysLog sysLog = new SysLog();
        sysLog.setIp(ip);
        sysLog.setMethod(adviceType+":"+clazz+"."+methodName);
        sysLog.setUsername(getUserName());
        sysLog.setVisitTime(new Date());

        //添加日志操作
        sysLogService.addLog(sysLog);
    }

    /***
     * 获取用户名字
     * @return
     */
    public String getUserName(){
        return SecurityContextHolder.getContext().getAuthentication().getName();
    }
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值