大家好,又见面了,我是你们的朋友全栈君。
登录安全——拦截器和过滤器或权限框架的使用
本次我们将采用两种方法实现登录的安全性,首先介绍拦截器和过滤器。
一、 过滤器和拦截器:
过滤器产生的时间/开始工作的时间: 进入Tomcat之后,但是在进servlet之前。Interceptor进入了servlet
所以拦截器拦截的是动作,而过滤器拦截的是不合理的跳转页面。
1、配置和使用拦截器。
<mvc:interceptors>
<mvc:interceptor>
<!-- 1.拦截所有的请求 -->
<mvc:mapping path="/**"/>
<!-- 2. mvc:exclude-mapping : 是一种拦截,可以放行或者对某个请求不拦截, -->
<mvc:exclude-mapping path="/user/doLogin.do"/>
<!-- 3. 告诉我们要用哪个拦截器 -->
<bean class="com.zhongruan.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
解释:除了login之外的请求都不允许执行
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//在拦截点执行前拦截,如果返回true,则不执行拦截点后的才做
//获取session
HttpSession session = request.getSession();
//获取访问路径
String uri = request.getRequestURI();
//indexOf函数:求出字符串内路径出现的下标
if(session.getAttribute("userInfo")!=null){
//登录成功,不拦截
return true;
}else{
//拦截成功
response.sendRedirect(request.getContextPath()+"user/doLogin.do");
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//处理过程中,执行拦截
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//执行完毕之后,返回前拦截
}
}
重写拦截点前拦截动作的函数:
如果登录成功,则证明是真正的用户,所以放弃拦截(拦截器也因此失效);如果登录失败,则重新返回登录界面,且无法输入其他动作跳转到其他界面。
2、配置和使用过滤器:
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.zhongruan.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/pages/*</url-pattern>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
上面是指请求所有界面都要通过过滤器,filter的实现如下:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//区别:Interceptor进入了servlet,所以重写的参数时HttpServletRequest/Response
// Filter没有进入Servlet.ServletRequest
// ServletRequest是接口,HttpServletRequest是实现,这里有些方法是HttpServletRequest中独有的,例如getSession
//所以要强制转换
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
//以下类似拦截器了
HttpSession session = request.getSession();
if(session.getAttribute("userInfo") == null && request.getRequestURI().indexOf("/user/doLogin.do") == -1){
// 没有登录,返回登录页面
response.sendRedirect(request.getContextPath()+"/user/doLogin.do");
}else{
//已经登录了,继续请求下一步操作
filterChain.doFilter(request,response);
}
}
同样,过滤器使用过后就会失效,如果是真正的用户,可以访问其他界面,否则不能在登录界面访问其他界面。
结果展示:
二、 使用权限框架Spring-Security
1、首先在pom.xml文件中导入框架需要的jar包
<!-- spring.security架包 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
2、配置web.xml文件
添加如下语句:
<!-- 配置 Spring-security;添加过滤器拦截所有请求 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、添加角色类:
由于验证机制是可以将用户类和管理员类区分开,登录后进入不同的界面,所以我们要增加一个角色类Role,它有三个属性:id,roleName和roleDesc,还有它们的get/set方法以及toString方法。
另外在UserInfo类中添加新的属性roleList(一个人可能对应多个角色)及其对应的方法。
4、添加Dao层:
新建一个名为“RoleDao”的接口类,并定义一个List findRoleByUserId(int userId);
方法。
<select id="findRoleByUserId" parameterType="java.lang.Integer" resultType="com.zhongruan.bean.Role">
select * from tb_Role where id in(select roleId from tb_user_role where userId=#{userId})
</select>
可以看出,这个sql语句使用了多表查询。先在tb_user_role表中根据userid查询该用户的roleid,再在tb_Role表中查找该roleid对应的角色是什么。
5、service层:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1. 查询当前登录的用户信息
UserInfo userInfo = userDao.doLogin(username);
System.out.println("获得的用户线信息为:"+ userInfo);
// 2. 查询当前的用户有多少角色
List<Role> roleList = roleDao.findRoleByUserId(userInfo.getId());
// 3. 需要把角色给放入用户中
userInfo.setRoleList(roleList);
// 4. 把查询到的User和Role数据 给到Spring-security中的内置对象User来管理
User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), getAuthority(userInfo.getRoleList()));
return user;
}
下面是getAuthority的代码:
private Collection<? extends GrantedAuthority> getAuthority(List<Role> roleList) {
List<SimpleGrantedAuthority> list = new ArrayList<>();
for(Role role:roleList){
list.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
}
return list;
}
6、准备spring-security文件:
<security:global-method-security pre-post-annotations="enabled" jsr250-annotations="enabled" secured-annotations="enabled"></security:global-method-security>
<!-- 配置不拦截的资源 -->
<security:http pattern="/login.jsp" security="none"/>
<security:http pattern="/failer.jsp" security="none"/>
<security:http pattern="/css/**" security="none"/>
<security:http pattern="/img/**" security="none"/>
<security:http pattern="/plugins/**" security="none"/>
<!--
配置具体的规则
auto-config="true" 不用自己编写登录的页面,框架提供默认登录页面
use-expressions="false" 是否使用SPEL表达式(没学习过)
-->
<security:http auto-config="true" use-expressions="true">
<!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER的角色" -->
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
<security:form-login login-page="/login.jsp"
login-processing-url="/login.do"
default-target-url="/index.jsp"
authentication-failure-url="/failer.jsp"
authentication-success-forward-url="/pages/main.jsp"/>
<!-- 关闭跨域请求 -->
<security:csrf disabled="true"/>
<!--退出并跳转到首页-->
<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp"></security:logout>
</security:http>
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式
<security:password-encoder ref="passwordEncoder"/> -->
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置加密类 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
7、login.jsp页面:
这里直接用login.do而不是doLogin.do(之前的函数已经被注释掉了)。这个login.do的实现是在框架里写所以我们不需要管。
Aside.jsp页面:
由于登录后会在左上角显示登录用户的头像和信息以及可以进行的操作,所以需要在下拉菜单的链接加上一句<security:authentication property=“principal.username”></security:authentication>
同时加上如下代码:
<security:authorize access="hasRole('ADMIN')">
<a
href="${pageContext.request.contextPath}/user/findAll.do?page=1&size=5"> <i
class="fa fa-circle-o"></i> 用户管理
</a>
</security:authorize>
意思是只有管理员拥有“用户管理”这个选项,普通用户界面不显示。
下面是运行结果展示:
如果是输入了错误的用户名或密码:
如果是管理员身份成功登录:
如果是用户身份成功登录:
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125017.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...