spring结合shiro使用方法

首先是配置:
pom.xml:

<dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.2.1</version>
    </dependency>

web.xml:

  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

shiro.xml:

<!--Shiro的Web业务应用程序的主要业务层对象 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myShiroRealm" />
        <property name="cacheManager" ref="cacheManager" />
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>
<!--记住我管理 -->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cookie" ref="remeberMeCookie"/><!--注入cookie类-->
        <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/><!--加密的cookie值-->
    </bean>


    <!-- 項目自定义的Realm -->
    <bean id="myShiroRealm" class="com.gao.test.shiro.MyRealm">
        <property name="cacheManager" ref="cacheManager" />
    </bean>

    <!-- Shiro 的过滤层-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/login.jsp" /> <!--登陆页面-->
        <property name="successUrl" value="/index.jsp"/> <!--登陆成功跳转,或者成功跳转到指定-->
        <property name="unauthorizedUrl" value="/login.jsp" /><!--授权失败跳转到登陆-->
        <property name="filters">    
            <map>
                <entry key="rememberMe" value-ref="rememberFilter"></entry><!--这里加了一个自己写的表单过滤验证-->
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /success = authc          <!--authc是需要账号密码正确后能访问-->
                /succ = user,rememberMe   <!--user是可以用记住我访问-->
                /login = anon             <!--这里不需要授权就能访问-->
                /login.jsp = anon
                /logout.jsp = anon
                /index = anon
                /logout = anon
                /** = user
            </value>
        </property>
    </bean>

    <!-- 用户授权信息Cache -->
    <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />

    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    <!-- AOP式方法级权限检查,注解方式 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

    <!--防止记住我登陆后没有session,自己写的表单过滤器-->
    <bean id="rememberFilter" class="com.gao.test.shiro.RememberRealm"/>

    <!--记住我cookie的设置-->
    <bean id="remeberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe"/>    <!--cookie名字-->   
        <property name="path" value="/"/>        <!--coolie存储在浏览器位置-->
        <property name="httpOnly" value="true"/>  <!--js脚本无法读取cookie,防止XSS攻击-->
        <property name="maxAge" value="604800"/>  <!--存储时间-->
    </bean>

代码:
realm授权规则:

public class MyRealm extends AuthorizingRealm {

    private static final String USER_NAME = "gao";  //测试用的账号密码
    private static final String PASSWORD = "123";
    //登陆后添加角色和权限用的
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Set<String> roleNames = new HashSet<String>();
        Set<String> permissions = new HashSet<String>();
        roleNames.add("admin");//添加角色
        permissions.add("success.jsp");  //添加权限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
        info.setStringPermissions(permissions);
        return info;
    }

    //登陆验证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //拿到账号密码令牌
        UsernamePasswordToken ut = (UsernamePasswordToken) token;
        String username = ut.getUsername();
        //这里只需要验证一下账号是否存在即可,然后通过数据库拿到密码(或者涉及到盐的密码)
        if(username.equals(USER_NAME)){
            //这里就直接把账号,查到的密码,还有类名交给shiro,他会自己去验证是否正确
            return new SimpleAuthenticationInfo(username,PASSWORD,getName());
        }else{
            //这里抛出没有用户的错误
            throw new AuthenticationException();
        }
    }
}

表单过滤:

public class RememberRealm extends FormAuthenticationFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        //这里的目的是通过记住我登陆后,从shiro中拿到账号id或者用户名,然后查询到用户信息,放到session
        Subject subject = getSubject(request, response);
        Session session = subject.getSession();
        Object principal = subject.getPrincipal();
        session.setAttribute("user",principal.toString());

        return  subject.isRemembered()||subject.isAuthenticated();
    }
}

web处理层:

@Controller
public class IndexController {
    //这里如果强制进入登录页,则退出从新登录
    @RequestMapping("/index")
    public String index() {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            subject.logout();
        }
        return "login";
    }

    //测试用
    @RequestMapping("/succ")
    public String success() {
        return "succ";
    }
    //登录页面
    @RequestMapping("/login")
    public String login(String user, String pass, String remember,HttpServletRequest req) {
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(user, pass, (remember == null || remember == "") ? false : true);
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isAuthenticated()) {
                subject.login(token);
            }
            HttpSession session = req.getSession();
            session.setAttribute("user",user);
        } catch (Exception e) {
            System.out.println("登录失败");
            return "error";
        }
        return "success";
    }

    //这里退出功能,并且能够清楚浏览器cookie
    @RequestMapping("/logout")
    public String logout(HttpServletRequest re, HttpServletResponse res) {
        Cookie[] cookies = re.getCookies();
        if (cookies != null) {
            Arrays.stream(cookies).forEach(
                    cookie -> {
                        if (cookie.getName().equals("rememberMe")) {
                            Cookie rem = new Cookie("rememberMe", null);
                            rem.setPath("/");
                            rem.setMaxAge(0);
                            res.addCookie(rem);
                        }
                    }
            );
        }
        Subject subject = SecurityUtils.getSubject();
        if(subject.isAuthenticated()){
            subject.logout();
        }
        return "logout";
    }

}


下面是使用ajax方式登陆:
shiro会走自己的验证,不需要你在controller写登陆接口了.下面是设置规则和接收参数
shiro.xml:

 <bean id="ajax" class="com.gao.test.shiro.AjaxRealm">
        <property name="usernameParam" value="user"/>     <!--这里的value是你表单提交的字段-->
        <property name="passwordParam" value="pass"/>
        <property name="rememberMeParam" value="rememberMe"/>    <!--这里接收的值是一个boolean类型-->
        <property name="loginUrl" value="/login"/>         <!--登陆地址,通过这个地址判断是不是进行登陆操作-->
    </bean>
 <property name="filters">
            <map>
                <entry key="ajaxRealm" value-ref="ajax"></entry>   <!--加入到过滤链-->  
            </map>
        </property>
<property name="filterChainDefinitions">
            <value>
                /login = ajaxRealm                 <!--这里的要与自定义过滤器名称相同,才会走自定义的过滤器-->
                /success = authc
                /succ = authc,rememberMe
                /login.jsp = anon
                /logout.jsp = anon
                /index = anon
                /logout = anon
                /** = authc
            </value>
        </property>

下面是代码:

//继承表单过滤器
public class AjaxRealm extends FormAuthenticationFilter  {
    //这里是没有登陆时首先运行这里(这里可以依据需求自己更改)
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        //返回没有登陆信息
        httpServletResponse.setContentType("application/json; charset=utf-8");
        //判断请求地址是否为/login
        if(this.isLoginRequest(request, response)) {
            //这里判断是否为post方式
            if(this.isLoginSubmission(request, response)) {
                //是post方式,则进行登陆
                return this.executeLogin(request, response);
            } else {
               /* PrintWriter writer = httpServletResponse.getWriter();
                PrintWriter out = httpServletResponse.getWriter();
                out.println("{\"success\":fail,\"message\":\"不能用get请求\"}");
                out.flush();
                out.close();
                return false;*/
                //或者用通过get登陆也验证一下代码
                return this.executeLogin(request, response);
            }
        } else {
            //如果请求地址不是登陆,则响应信息
            PrintWriter writer = httpServletResponse.getWriter();
            PrintWriter out = httpServletResponse.getWriter();
            out.println("{\"success\":fail,\"message\":\"没有登陆\"}");
            out.flush();
            out.close();
            return false;
        }
    }



    /**
     * 当登录成功
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest
                .getHeader("X-Requested-With"))) {// 不是ajax请求
            issueSuccessRedirect(request, response);
        } else {
            httpServletResponse.setCharacterEncoding("UTF-8");
            PrintWriter out = httpServletResponse.getWriter();
            out.println("{\"success\":true,\"message\":\"登入成功\"}");
            out.flush();
            out.close();
        }
        return false;
    }

    /**
     * 当登录失败
     * @param token
     * @param e
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (!"XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request)
                .getHeader("X-Requested-With"))) {// 不是ajax请求
            //setFailureAttribute(request, e);

            try {
                httpServletResponse.sendRedirect("/login.jsp");
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            return false;
        }
        try {
            httpServletResponse.setContentType("text/html; charset=utf-8");
            PrintWriter out = httpServletResponse.getWriter();
            String message = e.getClass().getSimpleName();
            if ("IncorrectCredentialsException".equals(message)) {
                out.println("{\"success\":false,\"message\":\"密码错误\"}");
            } else if ("UnknownAccountException".equals(message)) {
                out.println("{\"success\":false,\"message\":\"账号不存在\"}");
            } else if ("LockedAccountException".equals(message)) {
                out.println("{\"success\":false,\"message\":\"账号被锁定\"}");
            } else if("AuthenticationException".equals(message)){
                out.println("aa");
            } else {
                out.println("{\"success\":false,\"message\":\"未知错误\"}");
            }
            out.flush();
            out.close();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return false;
    }
}

猜你喜欢

转载自blog.csdn.net/myth_g/article/details/80268165