1.添加shiro框架包
<!--shiro权限管理-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
2.在web.xml中添加过滤器,意思是url被该过滤器拦截做权限验证,验证通过才给到controller。
<!-- 配置 Shiro 的 Filter -->
<filter>
<description>shiro 权限拦截</description>
<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>
3.配置shiro的applicationContext
新建一个recources/applicationContext-shiro.xml (注意按自己的mvc配置命名)
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 启用shrio授权注解拦截方式 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 装配 securityManager -->
<property name="securityManager" ref="securityManager"/>
<!-- 配置登陆页面 -->
<property name="loginUrl" value="/login.html"/>
<!-- 登陆成功后的一面 -->
<property name="successUrl" value="/success.html"/>
<property name="unauthorizedUrl" value="/403.html"/>
<!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截. -->
<property name="filterChainDefinitions">
<value>
/login.html = anon
/subLogin = anon
/roles = roles[admin]
/testPerms = roles[admin],perms[ordertable:add]
/** = roles["admin"]
</value>
</property>
</bean>
<!-- 配置进行授权和认证的 Realm -->
<bean id="myRealm" class="cn.longteng.shiro.realm.ShiroDbRealm">
</bean>
<!-- 配置 Shiro 的 SecurityManager Bean. -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
</beans>
4.自定义Realm,realm时shiro验证身份和权限的逻辑控制器,里面理论上是放账号和权限的数据库查询和判断逻辑
新建一个ShiroDbRealm继承AuthorizingRealm,会要求你重写两个方法
权限授权---doGetAuthorizationInfo(PrincipalCollection principals)
账号认证---doGetAuthenticationInfo(AuthenticationToken token)
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.Set;
/**
* @Description:
* @Author longteng
* @Version v2.0
* @Date: 2018/9/6
* @since:
*/
public class ShiroDbRealm extends AuthorizingRealm {
//授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
{
System.out.println("数据库进行权限认证");
//通过传过来的信息中,获取用户名
String userName = (String) principals.getPrimaryPrincipal();
//从数据库获取角色与权限
Set<String> setsR = new HashSet<String>();
Set<String> setsP = new HashSet<String>();
getRolesAndPermissionOnDB(userName,setsR,setsP);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(setsR);;
simpleAuthorizationInfo.setStringPermissions(setsP);
return simpleAuthorizationInfo;
}
//认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
System.out.println("数据库进行账号认证");
//通过传过来的信息中,获取用户名
String userName = (String) token.getPrincipal();
//通过用户名到数据库中获取凭证
String password =getPassOnDB(userName);
if (password == null)
{
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, password, "CustomRealm");
return authenticationInfo;
}
private String getPassOnDB(final String username)
{
//从数据库里查出密码是多少
//………………
return "123456";//假设查出来是123456
}
private void getRolesAndPermissionOnDB(String username, Set<String> setsR, Set<String> setsP)
{
//从数据库里查出该账号的授权数据
//…………
//假设查出来如下
setsR.add("admin"); //admin角色
setsP.add("ordertable:add");//权限
setsP.add("ordertable:del");
}
}
5.添加以下介个xml用作登陆验证与提示
403.html:
{"ret":"fail","msg":"未经身份验证"}
Success.html:
{"ret":"success","msg":"登陆成功"}
Login.html:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<table>登陆</table>
</head>
<body>
<form action="subLogin" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password" ><br>
<input type="submit" name="登陆">
</form>
</body>
</html>
Logout.html:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<table>是否登出:</table>
</head>
<body>
<form action="subLogout" method="post">
<input type="submit" name="登出">
</form>
</body>
</html>
6.编辑subLogin接口和sunLogout接口
(1)创建类UserController编写接口
import cn.longteng.web.comtroller.entity.User;
import cn.longteng.web.utils.RetMsg;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/**
* @Description:
* @Author longteng
* @Version v2.0
* @Date: 2018/9/6
* @since:
*/
@Controller
public class UserController
{
@RequestMapping(value = "/subLogin", method = RequestMethod.POST, produces="text/html; charset=UTF-8")
@ResponseBody
public String subLogin(User user)
{
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
try
{
token.setRememberMe(user.isRemenmberMe());
subject.login(token);
}
catch (AuthenticationException e)
{
return RetMsg.FL(e.toString());
}
return RetMsg.SU("登陆成功");
}
@RequestMapping(value = "/subLogout", method = RequestMethod.POST, produces="text/html; charset=UTF-8")
@ResponseBody
public String subLogout()
{
Subject subject = SecurityUtils.getSubject();
try
{
subject.logout();
}
catch (AuthenticationException e)
{
return RetMsg.FL(e.toString());
}
return RetMsg.SU("登出成功");
}
}
(2)创建类User类用于参数接收。
public class User
{
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
7.好了,我们可以开始我们的接口开发了。配合前面的配置
8.我们来测试以下成果
(1)运行起来后你会发现访问任何接口都会跳转到login.html
(2)只有当我们输入账号密码登陆后,接口才能正常调用
(3)接口就可以使用了
9.题外话,如果你做前后端分离的应用,例如为Android的app提供接口,我们怎么进行验证呢?
(1)首先推荐安装一个postman测试工具
(2)按以下配置设置接口
(3)调用成功后查看cookie
(4)配置带该cookie的接口
10.Ok大功告成
当然了,还有MD5密码加密加盐,还有自定义cookie,还有记住验证,还有验证有效期,还有redis的缓存,还有账号比对的优化不要去查那么多次数据。我在后面的的文章给大家介绍。该代码只是shiro结合mvc的原型。还有很多优化和技巧要我们去挖掘,笔者也是才写完一个功能架构,写出这篇文章,大家互相学习,不喜勿喷。(以上代码说明也许有部分遗漏或者错误,如有疑问请下载完整代码)。建议拥有springmvc基础再学习该知识