java鬼混笔记:shiro 6、shiro和spring整合、数据库方式认证登录

来源:互联网 发布:淘宝小二在哪里找 编辑:程序博客网 时间:2024/06/14 09:46

这次的笔记是记录shiro和spring的整合,整合后连接数据库进行身份认证。

完整的项目下载路径(项目下载网上的hui框架来着,什么鬼文件都在里面,暂清除,所以很多):

http://download.csdn.net/download/u013845177/9992748

相关的lib包路径:

http://download.csdn.net/download/u013845177/9992728


首先在web.xml加上下面几行代码

<filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><!-- true由servlet容器控制filter的生命周期 --><init-param><param-name>targetFilterLifecycle</param-name><param-value>true</param-value></init-param><!-- targetBeanName 和 sprin中的bean中的id一样 --><init-param><param-name>targetBeanName</param-name><param-value>shiroFilter</param-value></init-param></filter><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

接着添加一个applicationContext-shiro.xml文件,内容如下(代码里有注释)

<?xml version="1.0" encoding="utf-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd                        http://www.springframework.org/schema/tx                        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd                        http://www.springframework.org/schema/aop                        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd                        http://www.springframework.org/schema/context                        http://www.springframework.org/schema/context/spring-context-3.2.xsd                        http://www.springframework.org/schema/util                        http://www.springframework.org/schema/util/spring-util-3.2.xsd                        http://www.springframework.org/schema/task                        http://www.springframework.org/schema/task/spring-task-3.2.xsd"><!-- 1、这里的id要和web.xml中配置的targetBeanName下面的value一致--><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager" /><!-- 2、配置登录链接,如果用户没有登录就进行操作的话,就让他跳转到/login.do进行登录操作--><property name="loginUrl" value="/login.do" /><!-- successUrl认证成功后跳转的url,去掉,因为实际中,比如successUrl对应的是A页,我在访问C页面时,有一个功能是要登录才可以操作的,如果我配置了successUrl,那么我登录成功之后会跳转A页面,然后我再各种点点点才回到C页面,这就很蛋疼了,如果我没配置 successUrl,那么在登录之后,shiro会自动跳转到上一个url,也是登录页面前一个url,那就是C页面的url,也就是C页面跳转到登录页面后,成功登录后直接返回到C页面,我就可以继续在C页面做事了--><!-- <property name="successUrl" value="index.do"/> --><!-- 3.过滤器配置,有多个,百度就行,这里只有上两个就行(anon:意思是不用户用户登录,就可以访问,比如加载个jquery.js肯定不用登录就可以有了。authc:意思是通过认证之后才可以访问)--><property name="filterChainDefinitions"><value><!-- 这个意思是访问/ssiupload/xxxxxxxx请求时,不用认证用户是否登录,我这个是上传图片的测试例子-->/ssiupload/** = anon<!-- 这个是我测试上传图片的页面,去掉认证-->/up.jsp = anon<!-- 这里是logout而不是anon,设置成logout.的话,shiro自己清空session -->/logout.do = logout<!-- 下面都是常用的静态文件,js呀,css呀,images呀,登录面呀等,都是可以不用登录认证过直接使用的,所以都用anon -->/noPower.jsp = anon/favicon.ico = anon/login.jsp = anon/js/** = anon/css/** = anon<!--这里不是jar包的lib,是我用网上第三方框架它们自带的lib文件夹,也是一些插件而已-->/lib/** = anon/static/** = anon/temp/** = anon<!-- 这个是获取验证码的url,也是不用登录才可以访问的,不然不现实-->/iCode.do = anon<!--如果用户没权限操作的话,跳转到这个url,也可以不用登录操作的-->/noPower.do = anon<!-- 手机调用接口,暂时设置成不用认证后也只可以访问 -->/mobile/** = anon/checkLogin.do = anon<!--剩下的全部要认证通过才可以进行操作,没有认证后的操作自动跳转到/login.od-->/** = authc</value></property></bean><!-- 安全管理器 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="userRealm" /><!-- 自定义的realm --><property name="sessionManager" ref="sessionManager" /></bean><!-- 自定义 realm --><bean id="userRealm" class="cn.common.LSRealm"></bean><!-- session管理 --><bean id="sessionManager"class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"><!-- session的失效时长,单位毫秒 --><property name="globalSessionTimeout" value="8880000" /><!-- 删除失效的session --><property name="deleteInvalidSessions" value="true" /><property name="sessionDAO" ref="sessionDAO" /></bean><!-- sessionDao --><bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO" /></beans>

OK。。。先配置到这里

因为我们现在的通过数据库获取用户信息进行登录对比的,所以要自定义一个realm进行用户信息的对比。这里这定义一个LSRealm,同配置这个LSRealm到applicationContext-shiro.xml中,上面已经配置了

<!-- 自定义 realm --><bean id="userRealm" class="cn.common.LSRealm"></bean>

同时在applicationContext-shiro.xml中id="securityManager"的bean中加入<property name="realm" ref="userRealm" />,如下面代码:

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


LSRealm.java 代码如下(代码里有注释):

package cn.common;import java.util.ArrayList;import java.util.Collection;import java.util.List;import org.apache.commons.lang3.StringUtils;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.ehcache.EhCacheManager;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.session.Session;import org.apache.shiro.session.mgt.eis.SessionDAO;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.subject.support.DefaultSubjectContext;import org.springframework.beans.factory.annotation.Autowired;import cn.entity.Power;import cn.entity.Role;import cn.entity.User;import cn.service.UserService;public class LSRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;@Overridepublic void setName(String name) {// 1、给这个realm一个名字super.setName("LSRealm");}// 授权处理(这里讲的是认证,这块可以先不用看)@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {User user = (User) principals.getPrimaryPrincipal();user = userService.findByUserName(user.getUserName());// 重新获取权限信息 这里一定要重新加载, 不然清空了缓存但是user中的角色权限信息不清空,怎么改权限都没用System.out.println("..................................【刷新权限】"+user.getUserName());List<String> roles = new ArrayList<String>();List<String> permissions = new ArrayList<String>();for(Role r : user.getRole()) {roles.add(r.getName());for(Power p : r.getPower()) {permissions.add(p.getValue());}}SimpleAuthorizationInfo sa = new SimpleAuthorizationInfo();sa.addRoles(roles);// 设置角色sa.addStringPermissions(permissions);// 设置权限return sa;}// 2、这里是认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//3、 获取token里的账号,就是登录时传过来的的账号String userName  = String.valueOf(token.getPrincipal());if(StringUtils.isBlank(userName)) {// 4、如果账号是空的,就不返回个null,后面会捕获,怎么捕获,后面再说。return null;}User u = userService.findByUserName(userName);// 5、这里通过数据库进行获取用户信息的if(u == null) {// 6、如果不存在这个用户,返回空,后面会捕获,怎么捕获,后面再说。return null;}// 7、获取用户后,返回认证信息,进行密码对比(这里我的数据库里的密码是MD5加密的,前台传过来的密码也是MD5加密的((登录时密码md5加密后才传过来这样子安全点))return new SimpleAuthenticationInfo(u, u.getPassword(), this.getName());}}


// 上面成功登录后,就会跳转到你登录前的页面,如果登录失败后,会根据applicationContext-shiro.xml中的<property name="loginUrl" value="/login.do" />跳转到login.do中,现在看看login.do怎么工作的

loginC.java登录控制层代码如下:

package cn.controller;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.UnknownAccountException;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class LoginC extends ControllerSupport{// 1、登录页面url@RequestMapping("login")public String login(Model model, HttpServletRequest request) {// 2、设置一个basePath, 这样就可以在jsp页面中直接用户${basePath}获取项目名getSession().setAttribute("basePath", request.getServletContext().getContextPath());// 3、这是核心, "shiroLoginFailure"是shiro跳转到这个url时带的内容(FormAuthenticationFilter.class中可以看到)String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");if(exceptionClassName!=null){if (UnknownAccountException.class.getName().equals(exceptionClassName)) {// 4、如果登录认证后账号不存在,那么shiroLoginFailure = UnknownAccountException.class.getName()model.addAttribute("msg", "账号不存在");} else if (IncorrectCredentialsException.class.getName().equals(// 5、同理,如果登录认证后密码不正确,那么shiroLoginFailure = IncorrectCredentialsException.class.getName()exceptionClassName)) {model.addAttribute("msg", "密码不正确");}else {// 未知错误model.addAttribute("msg", "未知错误");}}// 6、登录失败或者要登录的页面return "login";}// 系统的主页@RequestMapping("index")public String index(Model model, String page) {model.addAttribute("page", page);return "index";}// 退出登录@RequestMapping("logout")public String logout() {getSession().invalidate();return "login";}// 没有权限页面@RequestMapping("noPower")public String noPower() {return "noPower";}}

OK... 后台功能基本就这个样子, 那么在登录时,登录的jsp页面有个地方要注意一下!!!

平时jsp页面上账号和密码的代码是:

<input name="username" type="text" placeholder="账户" ><input name="password" type="password" placeholder="密码">


注意!!!账户的name必须等于username(注意username中的n是小写),这是为什么,那是因为shiro的表单认证FormAuthenticationFilter中它自己写死,看FormAuthenticationFilter中的代码
public class FormAuthenticationFilter extends AuthenticatingFilter {    //TODO - complete JavaDoc    public static final String DEFAULT_ERROR_KEY_ATTRIBUTE_NAME = "shiroLoginFailure";// 跳转返回登录页面的attribute的key    public static final String DEFAULT_USERNAME_PARAM = "username";// 1、look,username中的u是小写的    public static final String DEFAULT_PASSWORD_PARAM = "password";// 2、密码这个也是小写的    public static final String DEFAULT_REMEMBER_ME_PARAM = "rememberMe";    private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);    private String usernameParam = DEFAULT_USERNAME_PARAM;    private String passwordParam = DEFAULT_PASSWORD_PARAM;    private String rememberMeParam = DEFAULT_REMEMBER_ME_PARAM;    private String failureKeyAttribute = DEFAULT_ERROR_KEY_ATTRIBUTE_NAME;    ......// 截取一部份就行了  
不想用shiro自带的怎么办,很简单,自定义一个FormAuthenticationFilter就OK。我这就自定义一个LSFormAuthenticationFilter.java(后面认证码还用到这个类),上代码:

package cn.common;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;// 自定义登录表单认证public class LSFormAuthenticationFilter extends FormAuthenticationFilter {@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue)throws Exception {return super.onAccessDenied(request, response, mappedValue);}}


// 接着在 applicationContext-shiro.xml中配置一下

<!-- 配置自定义的form过滤器 --><bean id="LSFormAuthenticationFilter"class="cn.common.LSFormAuthenticationFilter"><!-- 表单中账号的input名称 --><property name="usernameParam" value="userName" /><!-- 原来是FormAuthenticationFilter.DEFAULT_USERNAME_PARAM = "username",我这里换成大写的 "userName", value可自定义,要jsp页面对应就行--><!-- 表单中密码的input名称 --><property name="passwordParam" value="password" /></bean>
同时在 applicationContext-shiro.xml中的<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"></bean>中加入下面代码

<property name="filters"><map><entry key="authc" value-ref="LSFormAuthenticationFilter" /><!-- 配置自定义的form认证过滤器 --></map></property>

OK。。。完毕。下面讲认证码处理,毕竟FormAuthenticationFilter没有认证码功能

阅读全文
0 0