springmvc集成shiro登录失败处理操作

网友投稿 289 2022-11-20


springmvc集成shiro登录失败处理操作

一般的登录流程会有:用户名不存在,密码错误,验证码错误等..

在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理。

shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制。

shiro的会话管理和缓存管理不在本文范围内。

下面通过登录失败的处理流程来介绍springmvc与shiro的集成。

依赖项目

依赖名称 

版本

spring

4.1.4.RELEASE

shiro

1.2.2

self4j

1.7.5

log4j

1.2.17

在web.xml里配置shiro

shiroFilter

org.springframework.web.filter.DelegatingFilterProxy

targetFilterLifecycle

true

shiroFilter

/*

新建一个spring-context-shiro.xml配置shiro相关信息,使用spring加载

xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:context="http://springframework.org/schema/context"

xsi:schemaLocation="

http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans-3.2.xsd

http://springframework.org/schema/context http://springframework.org/schema/context/spring-context-3.2.xsd"

default-lazy-init="true">

Shiro Configuration

          

/sys/login = authc

/sys/logout = logout

/sys/** = user

xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:context="http://springframework.org/schema/context"

xsi:schemaLocation="

http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans-3.2.xsd

http://springframework.org/schema/context http://springframework.org/schema/context/spring-context-3.2.xsd"

default-lazy-init="true">

Shiro Configuration

          

/sys/login = authc

/sys/logout = logout

/sys/** = user

新建一个登录认证过滤器FormAuthenticationFilter.java

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import org.apache.shiro.authc.AuthenticationToken;

import org.apache.shiro.web.util.WebUtils;

import org.springframework.stereotype.Service;

/**

* 表单验证(包含验证码)过滤类*/

@Service

public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {

public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";

private String captchaParam = DEFAULT_CAPTCHA_PARAM;

public String getCaptchaParam() {

return captchaParam;

}

protected String getCaptcha(ServletRequest request) {

return WebUtils.getCleanParam(request, getCaptchaParam());

}

protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {

String username = getUsername(request);

String password = getPassword(request);

String locale = request.getParameter("locale");

if (password == null) {

password = "";

}

boolean rememberMe = isRememberMe(request);

String host = getHost(request);

String captcha = getCaptcha(request);

return new UsernamePasswordToken(username, password.toCharArray(),locale, rememberMe, host, captcha);

}

}

新建令牌类UsernamePasswordToken.java

package com.chunhui.webservice.modules.sys.security;

/**

* 用户和密码(包含验证码)令牌类*/

public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {

private static final long serialVersionUID = 1L;

private String captcha;

private String locale;

public String getCaptcha() {

return captcha;

}

public void setCaptcha(String captcha) {

this.captcha = captcha;

}

public String getLocale() {

return locale;

}

public void setLocale(String locale) {

this.locale = locale;

}

public UsernamePasswordToken() {

super();

}

public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha) {

super(username, password, rememberMe, host);

this.captcha = captcha;

}

public UsernamePasswordToken(String username, char[] password, String locale,boolean rememberMe, String host, String captcha) {

super(username, password, rememberMe, host);

this.captcha = captcha;

this.locale = locale;

}

}

最后一个是认证实现类SystemAuthorizationRealm:

package com.chunhui.webservice.modules.sys.security;

import java.io.Serializable;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.annotation.PostConstruct;

import com.chunhui.webservice.common.utils.EmployeeType;

import com.chunhui.webservice.common.utils.VertifyStatus;

import org.apache.commons.lang3.StringUtils;

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.*;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;

import org.apache.shiro.authz.AuthorizationInfo;

import org.apache.shiro.authz.SimpleAuthorizationInfo;

import org.apache.shiro.cache.Cache;

import org.apache.shiro.realm.AuthorizingRealm;

import org.apache.shiro.session.Session;

import org.apache.shiro.subject.PrincipalCollection;

import org.apache.shiro.subject.SimplePrincipalCollection;

import org.apache.shiro.subject.Subject;

import org.springframework.context.annotation.DependsOn;

import org.springframework.stereotype.Service;

import com.chunhui.webservice.common.servlet.ValidateCodeServlet;

import com.chunhui.webservice.common.utils.SpringContextHolder;

import com.chunhui.webservice.modules.sys.entity.Employee;

import com.chunhui.webservice.modules.sys.entity.Menu;

import com.chunhui.webservice.modules.sys.service.SystemService;

import com.chunhui.webservice.modules.sys.utils.SystemUtils;

import com.chunhui.webservice.modules.sys.web.LoginController;

/**

* 系统安全认证实现类*/

@Service

@DependsOn({ "employeeDao", "roleDao", "menuDao" })

public class SystemAuthorizingRealm extends AuthorizingRealm {

private SystemService systemService;

/**

* 认证回调函数, 登录时调用

*/

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {

UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

// 判断验证码

Session session = SecurityUtils.getSubject().getSession();

// 设置独立的session会话超时时间 session.setTimeout(60000);

String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);

if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)) {

throw new CaptchaException("验证码错误!");

}         //如果帐号不存在,输出

//throw new UnknownAccountException();

//如果帐号被禁用,输出

//throw new DisabledAccountException();

//保存登录时选择的语言

SecurityUtils.getSubject().getSession().setAttribute("locale", token.getLocale());

try{

SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(new Principal(employee), employee.getPassword(), getName());

return info;

}catch (Throwable t){

t.printStackTrace();

throw new AuthenticationException();

}

}/**

* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用

*/

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

Principal principal = (Principal) getAvailablePrincipal(principals);

Employee employee = getSystemService().getEmployeeByName(principal.getUsername());

if (employee != null) {

SystemUtils.putCache("employee", employee);

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

List

for (Menu menu : list) {

if (StringUtils.isNotBlank(menu.getPermission())) {

// 添加基于Permission的权限信息

for (String permission : StringUtils.split(menu.getPermission(), ",")) {

info.addStringPermission(permission);

}

}

}

// 更新登录IP和时间

getSystemService().updateEmployeeLoginInfo(employee.getId());

return info;

} else {

return null;

}

}

/**

* 清空用户关联权限认证,待下次使用时重新加载

*/

public void clearCachedAuthorizationInfo(String principal) {

SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());

clearCachedAuthorizationInfo(principals);

}

/**

* 清空所有关联认证

*/

public void clearAllCachedAuthorizationInfo() {

Cache cache = getAuthorizationCache();

if (cache != null) {

for (Object key : cache.keys()) {

cache.remove(key);

}

}

}

/**

* 获取系统业务对象

*/

public SystemService getSystemService() {

if (systemService == null) {

systemService = SpringContextHolder.getBean(SystemService.class);

}

return systemService;

}

/**

* 授权用户信息

*/

public static class Principal implements Serializable {

private static final long serialVersionUID = 1L;

private String id;

private String username;

private String realname;

private Map cacheMap;

public Principal(Employee employee) {

this.id = employee.getId();

this.username = employee.getUsername();

this.realname = employee.getRealname();

}

public String getId() {

return id;

}

public String getUsername() {

return username;

}

public String getRealname() {

return realname;

}

public Map getCacheMap() {

if (cacheMap == null) {

cacheMap = new HashMap();

}

return cacheMap;

}

}

}

那么在jsP页面,可以通过获取登录异常具体的异常类型来在页面显示错误原因

<%String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%>

       


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:浅谈springmvc 通过异常增强返回给客户端统一格式
下一篇:解决Spring Boot 多模块注入访问不到jar包中的Bean问题
相关文章

 发表评论

暂时没有评论,来抢沙发吧~