`

shiro在springmvc里面的集成使用

 
阅读更多

原文地址:http://peihexian.iteye.com/blog/2155516

需要在项目里面引入的maven依赖:

 

   <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.9</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>1.2.3</version>
        </dependency>

 

如果项目是hibernate的,以前的时候ehcache可能不是单例的,因为shiro里面也使用到了ehcache做缓存,和hibernate的ehcache缓存配置有冲突,所以需要对hibernate的ehcache部分做些调整,调整如下:

 

 <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <!--
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</prop>
                -->
                <prop key="hibernate.cache.region.factory_class">
                    org.hibernate.cache.SingletonEhCacheRegionFactory
                </prop>
                <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.use_structured_entries">true</prop>
                <prop key="hibernate.cache.provider_configuration_file_resource_path">WEB-INF/classes/ehcache.xml</prop>
                <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
            </props>
        </property>
        <property name="packagesToScan">
            <list>
                <value>com.xxx.entity</value>
            </list>
        </property>
    </bean>

 

上面红色的文字部分是需要调整的内容。

 

 

既然用到了ehcache,ehcahce.xml文件里面的配置内容如下:

 

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="java.io.tmpdir" />

    <defaultCache maxElementsInMemory="10000" eternal="false"
                  timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
    <cache name="org.hibernate.cache.UpdateTimestampsCache"
           maxElementsInMemory="5000" eternal="true" overflowToDisk="true" />
    <cache name="org.hibernate.cache.StandardQueryCache"
           maxElementsInMemory="10000" eternal="false" timeToLiveSeconds="120"
           overflowToDisk="true" />
    <!-- 登录记录缓存 锁定10分钟 -->
    <cache name="passwordRetryCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="authenticationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="shiro-activeSessionCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
</ehcache>

 

 

然后是web.xml文件里面加过滤器,注意要写在springmvc的filter前面

 

    <!-- shiro 安全过滤器 -->
    <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <async-supported>true</async-supported>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all -->
    <!-- requests.  Usually this filter mapping is defined first (before all others) to -->
    <!-- ensure that Shiro works in subsequent filters in the filter chain:             -->
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

 

然后就是shiro相关的spring配置参数文件了

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 缓存管理器 使用Ehcache实现-->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
    </bean>

    <bean id="passwordHelper" class="com.shinowit.framework.security.PasswordHelper">
    </bean>

    <!-- 凭证匹配器 -->
    <bean id="credentialsMatcher"
          class="com.shinowit.framework.security.credentials.RetryLimitSimpleCredentialsMatcher">
        <constructor-arg ref="cacheManager"/>
        <property name="passwordHelper" ref="passwordHelper"/>
    </bean>


    <bean id="shiro_user_dao" class="com.shinowit.framework.security.dao.UserDAO">
        <property name="jt" ref="jdbcTemplate"/>
    </bean>

    <!-- Realm实现 -->
    <bean id="userRealm" class="com.shinowit.framework.security.realm.UserRealm">
        <property name="userDAO" ref="shiro_user_dao"/>
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <!--密码校验接口-->
        <property name="cachingEnabled" value="true"/>
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>

    <!-- 会话ID生成器 -->
    <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>

    <!-- 会话Cookie模板 -->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="sid"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="180000"/>
    </bean>

    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="2592000"/>
        <!-- 30天 -->
    </bean>

    <!-- rememberMe管理器 -->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cipherKey"
                  value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
        <property name="cookie" ref="rememberMeCookie"/>
    </bean>

    <!-- 会话DAO -->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
        <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
    </bean>

    <!-- 会话验证调度器 -->
    <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
        <property name="sessionValidationInterval" value="1800000"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>

    <!-- 会话管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="globalSessionTimeout" value="1800000"/>
        <property name="deleteInvalidSessions" value="true"/>
        <property name="sessionValidationSchedulerEnabled" value="true"/>
        <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
        <property name="sessionDAO" ref="sessionDAO"/>
        <property name="sessionIdCookieEnabled" value="true"/>
        <property name="sessionIdCookie" ref="sessionIdCookie"/>
    </bean>

    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
        <property name="sessionManager" ref="sessionManager"/>
        <property name="cacheManager" ref="cacheManager"/>
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>

    <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    </bean>

    <!--下面的loginUrl有两个必要条件,一个登陆校验失败以后会强制客户端redirect到这个url,
    另外一个是登陆的表单(含有用户名及密码)必须action到这个url-->
    <!-- 自定义的能够接收校验码的身份验证过滤器
     跳转问题太他妈诡异了,不用了,自己写代码控制如何跳转了
    <bean id="formAuthenticationFilter" class="com.shinowit.framework.security.filter.ValidFormAuthenticationFilter">
        <property name="usernameParam" value="loginName"/>
        <property name="passwordParam" value="loginPass"/>
        <property name="loginUrl" value="/login/"/>
    </bean>
-->

    <!-- Shiro的Web过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login/"/>
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
        <property name="filters">
            <map>
                <entry key="authc">
                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>
                </entry>
            </map>
            <!--
            <util:map>
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </util:map>
            -->
        </property>
        <property name="filterChainDefinitions">
            <value>
                /index.jsp = anon
                /validcode.jsp = anon
                /login/ = anon
                /static/** = anon
                /js/** = anon
                /img/** = anon
                /unauthorized.jsp = anon
                #/login/checklogin = authc
                /login/checklogin = anon
                /login/logout = logout
                /** = user
            </value>
        </property>
    </bean>

    <!-- Shiro生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>


</beans>

 

 

下面就是各种自己封装的java代码了

 

自定义的可以保存校验码的token类

package com.xxx.framework.security.token;

import org.apache.shiro.authc.UsernamePasswordToken;

/**
 * Created on 2014/11/11.
 */
public class CustomUsernamePasswordToken extends UsernamePasswordToken {

    //用于存储用户输入的校验码
    private String validCode;


    public CustomUsernamePasswordToken(String username, char[] password,boolean rememberMe, String host, String validCode) {
        //调用父类的构造函数
        super(username,password,rememberMe,host);
        this.validCode=validCode;
    }

    public String getValidCode() {
        return validCode;
    }

    public void setValidCode(String validCode) {
        this.validCode = validCode;
    }
}

 

 

提供正确的登录用户信息的基于jdbc的realm

package com.xxx.framework.security.realm;

import com.xxx.entity.SysUserEntity;
import com.xxx.framework.security.dao.UserDAO;
import com.xxx.framework.security.exception.ValidCodeException;
import com.xxx.framework.security.token.CustomUsernamePasswordToken;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;


public class UserRealm extends AuthorizingRealm {
    private static Logger logger = Logger.getLogger(UserRealm.class);

    private UserDAO userDAO;

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userDAO.getUserRoles(username));
        authorizationInfo.setStringPermissions(userDAO.findPermissions(username));

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        CustomUsernamePasswordToken login_token = (CustomUsernamePasswordToken) token;

        //校验码判断逻辑
        //取得用户输入的校验码
        String userInputValidCode = login_token.getValidCode();

        //取得真实的正确校验码
        String realRightValidCode = (String) SecurityUtils.getSubject().getSession().getAttribute("rand");

        if (null == userInputValidCode || !userInputValidCode.equalsIgnoreCase(realRightValidCode)) {
            logger.debug("验证码输入错误");
            throw new ValidCodeException("验证码输入不正确");
        }

        //以上校验码验证通过以后,查数据库
        String username = (String) token.getPrincipal();
        SysUserEntity user = userDAO.findByUsername(username);

        if (user == null) {
            throw new UnknownAccountException();//没找到帐号
        }

        if (Boolean.FALSE.equals(user.getValid())) {
            throw new LockedAccountException(); //帐号锁定
        }

        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getLoginName(), //用户名
                user.getLoginPass(), //密码
                getName()  //realm name
        );
        return authenticationInfo;
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

}

 

一个简单的自定义的处理校验码异常的类

 

package com.xxx.framework.security.exception;

import org.apache.shiro.authc.AuthenticationException;

/**
 * Created on 2014/11/11.
 */
public class ValidCodeException extends AuthenticationException {

    public ValidCodeException(String msg){
        super(msg);
    }
}

 

查询用户信息及权限信息的dao

 

package com.xxx.framework.security.dao;

import com.xxx.entity.SysUserEntity;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created on 2014/11/10.
 */
public class UserDAO {

    private JdbcTemplate jt;

    public void setJt(JdbcTemplate jt) {
        this.jt = jt;
    }

    public Set<String> getUserRoles(String loginName) {
        String sql = "select role from sys_user u, sys_role r,sys_user_to_role ur where u.login_name=? and u.user_code=ur.user_code and r.role_code=ur.role_code";
        return new HashSet(jt.queryForList(sql, String.class, loginName));
    }

    public Set<String> findPermissions(String loginName) {
        String sql = "select permission from sys_user u, sys_role r, sys_menu p, sys_user_to_role ur, sys_role_to_menu rp where u.login_name=? and u.user_code=ur.user_code and r.role_code=ur.role_code and r.role_code=rp.role_code and p.menu_id=rp.menu_id";
        return new HashSet(jt.queryForList(sql, String.class, loginName));
    }

    public SysUserEntity findByUsername(String loginName) {
        String sql = "select id, user_code,login_name, login_pass, valid from sys_user where login_name=?";
        List<SysUserEntity> userList = jt.query(sql, new BeanPropertyRowMapper(SysUserEntity.class), loginName);
        if (userList.size() == 0) {
            return null;
        }
        return userList.get(0);
    }
}

 

这个翻译过来叫啥合适呢?反正就是根据自定义的加密规则去进行密码匹配验证的类,爱JB叫啥叫啥吧

package com.xxx.framework.security.credentials;

import com.xxx.framework.security.PasswordHelper;
import com.xxx.framework.security.token.CustomUsernamePasswordToken;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;

import java.util.concurrent.atomic.AtomicInteger;

public class RetryLimitSimpleCredentialsMatcher extends SimpleCredentialsMatcher {

    private Cache<String, AtomicInteger> passwordRetryCache;

    private PasswordHelper passwordHelper;

    public RetryLimitSimpleCredentialsMatcher(CacheManager cacheManager) {
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    public void setPasswordHelper(PasswordHelper passwordHelper) {
        this.passwordHelper = passwordHelper;
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        CustomUsernamePasswordToken login_token = (CustomUsernamePasswordToken) token;

        String username = (String) token.getPrincipal();
        //retry count + 1
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if (retryCount == null) {
            retryCount = new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if (retryCount.incrementAndGet() > 5) {
            //if retry count > 5 throw
            throw new ExcessiveAttemptsException();
        }


        String user_input_login_pass = passwordHelper.encryptPassword(login_token.getUsername(), String.valueOf(login_token.getPassword()));
        Object db_login_password = getCredentials(info);
        //将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false
        boolean matches = super.equals(user_input_login_pass, db_login_password);

        if (matches) {
            //clear retry count
            passwordRetryCache.remove(username);
        }
        return matches;
    }
}

 

 

用户信息实体类

 

package com.xxx.entity;

import javax.persistence.*;
import java.util.List;

/**
 * Created on 2014/11/7.
 * 系统用户信息
 */
@Entity
@Table(name = "sys_user")
public class SysUserEntity {

    @GeneratedValue(strategy =GenerationType.IDENTITY)
    @Column(name = "id",insertable = false,updatable = false)
    private Integer id;

    @Id
    @Column(name = "user_code",length = 6)
    private String userCode;

    @Column(name = "login_name",length = 40,nullable = false,unique = true)
    private String loginName;

    @Column(name = "login_pass",length = 50)
    private String loginPass;

    @Column(name = "address",length = 200)
    private String address;

    @Column(name = "telphone",length = 30)
    private String telPhone;

    @Column(name = "qq",length = 15)
    private String qq;

    @Column(name = "email",length = 40)
    private String email;

    @Column(name = "mobile",length = 30)
    private String mobile;

    @Column(name = "sort_id")
    private Short sortId;

    @Column(name = "valid")
    private Boolean valid;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name="sys_user_to_role",joinColumns = { @JoinColumn(name = "user_code") }, inverseJoinColumns = { @JoinColumn(name = "role_code")})
    private List<SysRoleEntity> roleList;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserCode() {
        return userCode;
    }

    public void setUserCode(String userCode) {
        this.userCode = userCode;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getTelPhone() {
        return telPhone;
    }

    public void setTelPhone(String telPhone) {
        this.telPhone = telPhone;
    }

    public String getQq() {
        return qq;
    }

    public void setQq(String qq) {
        this.qq = qq;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public Short getSortId() {
        return sortId;
    }

    public void setSortId(Short sortId) {
        this.sortId = sortId;
    }

    public Boolean getValid() {
        return valid;
    }

    public void setValid(Boolean valid) {
        this.valid = valid;
    }

    public List<SysRoleEntity> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<SysRoleEntity> roleList) {
        this.roleList = roleList;
    }

}

 

 

还有一个md5工具类

package com.xxx.framework.security;

import java.security.MessageDigest;

public class PasswordHelper {


    /**
     * 根据用户名与密码做md5单向hash加密
     *
     * @param username 用户名
     * @param password 用户密码明文
     * @return md5(username+password)
     */

    public String encryptPassword(String username, String password) {

        String inStr = username + password;

        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
            return "";
        }
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();

    }
}

 

 

好了,我们的springmvc controller类是这么写的

 

package com.xxx.web.login;

import com.xxx.entity.SysUserEntity;
import com.xxx.framework.dao.BaseDAO;
import com.xxx.framework.security.PasswordHelper;
import com.xxx.framework.security.exception.ValidCodeException;
import com.xxx.framework.security.token.CustomUsernamePasswordToken;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping(value = "/login")
public class LoginController {

    private static final Logger logger = Logger.getLogger(LoginController.class);

    @Resource
    private BaseDAO<SysUserEntity> sys_user_dao;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String login() {
        return "/login/login";
    }

    @RequestMapping(value = "/checklogin", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> checkLogin(SysUserEntity login_user,HttpServletRequest request,@RequestParam("validCode")String validCode) {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("msg", "用户名或者密码错误!");
        result.put("success", "true");
        result.put("status", false);

        boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
        String host = request.getRemoteHost();

        //构造登陆令牌环
        CustomUsernamePasswordToken token = new CustomUsernamePasswordToken(login_user.getLoginName(), login_user.getLoginPass().toCharArray(), rememberMe,host,validCode);

        try{
            //发出登陆请求
            SecurityUtils.getSubject().login(token);
            //登陆成功
            HttpSession session = request.getSession(true);
            try {
                SysUserEntity user = sys_user_dao.findOneEntityByHql("from SysUserEntity where loginName=?", login_user.getLoginName());
                if (null != user) {
                    //根据输入的用户名和密码确实查到了用户信息
                    session.removeAttribute("rand");
                    session.setAttribute("current_login_user", user);
                    result.put("msg", "登录成功!");
                    result.put("status", true);
                    result.put("main_url", "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/main");
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            return  result;
        }catch (UnknownAccountException e){
            result.put("msg", "账号不存在!");
        }catch (IncorrectCredentialsException e){
            result.put("msg", "用户名/密码错误!");
        }catch (ExcessiveAttemptsException e) {
            result.put("msg", "账户错误次数过多,暂时禁止登录!");
        }catch (ValidCodeException e){
            result.put("msg", "验证码输入错误!");
        }catch (Exception e){
            result.put("msg", "未知错误!");
        }
        return result;
    }

    @RequestMapping(value="/logout")
    public String logout(){
        Subject currentUser = SecurityUtils.getSubject();
        if (SecurityUtils.getSubject().getSession() != null)
        {
            currentUser.logout();
        }
        return "redirect:/login/";
    }

    @Resource
    private PasswordHelper passwordHelper;

    @RequestMapping(value = "/fuck")
    @ResponseBody
    public Map<String, Object> fuck() {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("msg", "用户名或者密码错误!");
        result.put("success", "true");
        result.put("status", false);

        SysUserEntity user = sys_user_dao.findById(SysUserEntity.class, "0001");
        user.setLoginPass("a");
        String new_pass = passwordHelper.encryptPassword(user.getLoginName(), user.getLoginPass());
        user.setLoginPass(new_pass);

        sys_user_dao.update(user);

        return result;
    }

}

 

 哦,对了,里面那个fuck那个url是用来改密码的,因为数据库里面的密码是加密的,不这么整总也不可能知道对的md5值是多少。

 

但愿没有忘记什么内容,挺墨迹的,不过能跑起来以后后边关于权限和安全的处理就简单多了,写写注解或者标签就搞定了,很爽。

1
3
分享到:
评论
4 楼 pipilang3220119 2017-02-11  
请问,这样自己写的/login,在人直接请求/checklogin会报错,你是怎么解决的?
3 楼 苦逼老周 2015-12-09  
裴老,rememberMeManager里的cipherKey是做什么的?是加密rememberMeCookie的么?
2 楼 bobohenda 2015-10-06  
zyg345646335 写道
总结的很好,推荐一个框架整合:
http://43.249.81.29:8080/index.html
1 楼 zyg345646335 2015-08-24  
你的会话用了shiro的session,用户信息又存到了容器的sission,如果两个session超时时间不一样那不是会有问题?

相关推荐

    Shiro+SpringMVC 示例

    Apache Shiro 和 ...这个示例项目对于学习如何在没有数据库支持的情况下,使用Shiro和SpringMVC实现基本的用户认证和授权功能非常有帮助。开发者可以通过修改和扩展这个项目,以适应更复杂的业务需求和安全策略。

    cas结合 springmvc shiro 单点登录

    总之,这个项目为我们提供了一个使用CAS、SpringMVC和Shiro实现SSO的实例,对于理解和掌握这些技术的集成以及SSO的工作原理非常有帮助。在实际开发中,可以根据项目的具体需求进行调整和优化,以实现更高效、更安全...

    shiro_springmvc_demo

    通过"shiro_springmvc_demo"项目,你可以学习到如何在实际项目中配置和使用Shiro,了解其工作原理,并掌握如何结合SpringMVC实现权限控制。该项目包含的代码示例将帮助你更好地理解和应用这些知识点。在实际开发中,...

    spring、springmvc、shiro集成空框架

    总的来说,Spring、SpringMVC和Shiro的集成为空框架提供了一个坚实的基础,开发者可以在此基础上快速搭建企业级应用,提高开发效率并保证系统的安全性。理解这三个框架的核心概念和它们之间的协作方式,对于Java Web...

    基于shiro、springmvc、mybatis权限管理系统

    在权限管理场景中,SpringMVC可以与Shiro结合,实现请求级别的权限控制。 **MyBatis** MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数...

    Shiro+SpringMVC+Spring集成

    标题 "Shiro+SpringMVC+Spring集成" 涉及的是在Web开发中整合Apache Shiro、Spring MVC和Spring框架的过程。这三个组件都是Java Web开发中的重要工具,Shiro负责安全认证和授权,Spring MVC处理MVC模式的实现,而...

    shiro+springmvc整合demo

    在本示例中,"shiro+springmvc整合demo" 提供了一个基于SpringMVC和Apache Shiro的完整演示,同时结合了JPA(Java Persistence API,通过Hibernate实现)进行数据持久化。下面我们将详细探讨这些知识点。 **1. ...

    shiro+springmvc权限管理

    4. **Web集成**:Shiro可以轻松地与SpringMVC集成,通过Filter配置实现URL级别的访问控制,为Web应用提供安全入口。 **SpringMVC与Shiro的整合** 1. **配置Shiro Filter**:在SpringMVC的web.xml中配置Shiro的...

    shirodemo整合spring+springmvc+shiro

    5. **集成SpringMVC**:在SpringMVC的配置文件中,定义Shiro Filter,并将其注册到DispatcherServlet的过滤器链中。这通常通过`DelegatingFilterProxy`实现,它会代理到Spring容器中的Shiro Filter Bean。 6. **...

    shiro+ springMVC + Redis+mysql 实现 单点登录

    这个集成方案利用Shiro的强大安全功能,SpringMVC的Web处理能力,Redis的高效缓存特性,以及MySQL的稳定存储,共同构建了一个安全、高效的单点登录系统。开发者可以根据具体需求调整这些组件的配置,以适应不同的...

    shiro+springMVC+Mybatis

    在这个场景中,我们关注的是"shiro+springMVC+Mybatis"的整合应用,这是一种常见的技术栈,用于搭建基于Java的Web应用。这三个框架的结合,旨在提供用户认证、授权、会话管理和数据库操作等功能。 首先,让我们深入...

    shiro+springmvc整合

    在Spring MVC中集成Shiro,我们可以利用Shiro的Filter机制,通过配置Web应用的过滤链来实现安全控制。以下是整合步骤: 1. **添加依赖**:在项目中引入Shiro和Spring MVC的依赖库。通常在Maven或Gradle的配置文件中...

    springMVC整合shiro框架

    它能够直接与现有的MVC框架如SpringMVC集成,为Web应用提供安全控制。 2. **SpringMVC 整合 Shiro 的步骤** - **配置 Shiro-Filter**: 首先,在 `web.xml` 文件中配置 Shiro 过滤器,指定 `Filter-Class` 为 `org....

    shiro+springmvc+mybatis+maven

    在"shiro+springmvc+mybatis+maven"的集成中,通常步骤如下: 1. **配置Maven**:首先,在`pom.xml`中引入Shiro、SpringMVC、MyBatis以及它们的相关依赖。 2. **初始化Shiro**:创建Shiro的配置文件,如`shiro.ini`...

    shiro-springmvc-gradle整合

    4. **Eclipse集成**:使用`gradle eclipse`命令生成Eclipse工作空间元数据,使项目可以在Eclipse中顺利导入和构建。 5. **持续集成**:Gradle支持与其他CI/CD工具(如Jenkins、Travis CI)集成,实现自动化构建和...

    shiro 集成springmvc +hibernate mysql 登录认证以及授权

    在这个项目中,"shiro 集成springmvc +hibernate mysql 登录认证以及授权"是将Shiro与Spring MVC和Hibernate集成,用于构建一个基于MySQL数据库的完整的用户登录认证和权限管理解决方案。 1. **Shiro**:Apache ...

    spring+springMVC+shiro 完美例子

    总之,这个"spring+springMVC+shiro 完美例子"是一个很好的学习资源,帮助开发者深入理解如何在Java Web应用中集成和使用这些强大的框架,实现安全、高效的权限管理。通过分析和实践这个例子,开发者不仅可以提升...

    SpringMVC-Mybatis-Shiro-redis

    在SpringMVC-Mybatis-Shiro-Redis体系中,Shiro负责用户登录验证、权限控制和会话管理。开发者可以方便地定义角色和权限,实现细粒度的访问控制,保障系统的安全性。 Redis则作为一个高性能的键值存储系统,常用于...

    SpringMVC精品资源--Maven + Mysql + Shiro + SpringMVC + Spring.zip

    在Shiro中,你需要理解Subject、Realms、Caching等核心概念,以及如何配置Shiro与Spring进行集成,实现权限控制和登录逻辑。 SpringMVC是Spring框架的一部分,专为Web应用设计。它提供了模型-视图-控制器(MVC)...

Global site tag (gtag.js) - Google Analytics