版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39469809/article/details/78822949
- </pre><pre name="code" class="html"><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager"/>
- <property name="loginUrl" value="/login"/>
- <property name="successUrl" value="/first" />
- <property name="filters">
- <util:map>
- <entry key="authc" value-ref="formAuthenticationFilter"/>
- </util:map>
- </property>
- <property name="filterChainDefinitions">
- <value>
-
- /images/** = anon
- /js/** = anon
- /styles/** = anon
-
- /logout = logout
- /** = authc //设置授权才能访问
- </value>
- </property>
- </bean>
首先看一下Shiro中的web filter过滤器:
默认采用的认证过滤器filter是表单过滤器,默认登录的url是/login(只要没有认证的都会跳转到/login路径下),辅助登录成功url是/first。
默认登录url跳转到的页面是login.jsp如下:
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <%@ page contentType="text/html; charset=UTF-8"%>
- <%@ include file="/WEB-INF/jsp/tag.jsp"%>
- <html>
- <head>
- <TITLE>药品采购平台</TITLE>
- <meta http-equiv="pragma" content="no-cache">
- <meta http-equiv="cache-control" content="no-cache">
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-
- <LINK rel="stylesheet" type="text/css" href="${baseurl}styles/style.css">
- <LINK rel="stylesheet" type="text/css" href="${baseurl}styles/login.css">
- <LINK rel="stylesheet" type="text/css" href="${baseurl}js/easyui/themes/default/easyui.css">
- <LINK rel="stylesheet" type="text/css" href="${baseurl}js/easyui/themes/icon.css">
-
- <STYLE type="text/css">
- .btnalink {
- cursor: hand;
- display: block;
- width: 80px;
- height: 29px;
- float: left;
- margin: 12px 28px 12px auto;
- line-height: 30px;
- background: url('${baseurl}images/login/btnbg.jpg') no-repeat;
- font-size: 14px;
- color: #fff;
- font-weight: bold;
- text-decoration: none;
- }
- </STYLE>
- <%@ include file="/WEB-INF/jsp/common_js.jsp"%>
-
- <script type="text/javascript">
-
- //登录提示方法
- function loginsubmit() {
- $("#loginform").submit();
-
- }
-
- </SCRIPT>
- </HEAD>
- <BODY style="background: #f6fdff url(${baseurl}images/login/bg1.jpg) repeat-x;">
- <FORM id="loginform" name="loginform" action=""
- method="post">
- <DIV class="logincon">
-
- <DIV class="title">
- <IMG alt="" src="${baseurl}images/login/logo.png">
- </DIV>
-
- <DIV class="cen_con">
- <IMG alt="" src="${baseurl}images/login/bg2.png">
- </DIV>
-
- <DIV class="tab_con">
-
- <input type="password" style="display:none;" />
- <TABLE class="tab" border="0" cellSpacing="6" cellPadding="8">
- <TBODY>
- <TR>
- <TD>用户名:</TD>
- <TD colSpan="2"><input type="text" id="usercode"
- name="username" style="WIDTH: 130px" /></TD>
- </TR>
- <TR>
- <TD>密 码:</TD>
- <TD><input type="password" id="pwd" name="password" style="WIDTH: 130px" />
- </TD>
- </TR>
- <%-- <TR>
- <TD>验证码:</TD>
- <TD><input id="randomcode" name="randomcode" size="8" /> <img
- id="randomcode_img" src="${baseurl}validatecode.jsp" alt=""
- width="56" height="20" align='absMiddle' /> <a
- href=javascript:randomcode_refresh()>刷新</a></TD>
- </TR> --%>
-
- <TR>
- <TD colSpan="2" align="center"><input type="button"
- class="btnalink" onclick="loginsubmit()" value="登 录" />
- <input type="reset" class="btnalink" value="重 置" /></TD>
- </TR>
- </TBODY>
- </TABLE>
-
- </DIV>
- </DIV>
- </FORM>
- </BODY>
- </HTML>
form过滤器特点:只要是表单提交(条件:1.post 2.action路径为"")就相当于:
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
它会自动到Real中的方法进行身份认证:
- /**
- * 身份认证
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
- String userName = (String) token.getPrincipal();
- User user = userService.findByUsername(userName);
-
- if(user == null) {
- //抛出用户不存在异常
- throw new UnknownAccountException();//没找到帐号
- }
- if(user.getLocked()) {
- //抛出用户被锁定异常
- throw new LockedAccountException(); //帐号锁定
- }
- // 如果查询到返回认证信息AuthenticationInfo
- SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, user.getPassword(),ByteSource.Util.bytes(user.getCredentialsSalt()),
- this.getName());
-
- return simpleAuthenticationInfo;
- }
现应注意的是SimpleAuthenticationInfo这个方法的构造函数,因为它决定了凭证认证的方式:
1.
- public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {
- this.principals = new SimplePrincipalCollection(principal, realmName);
- this.credentials = credentials;
- }
构造器对应的默认任凭类,什么都不需要输入,没有加密算法,没有迭代次数,直接通过用户名和密码进行进行验证就可以。
- <bean id="userRealm" class="com.lgy.web.shiro.UserRealm">
-
-
- </bean>
2.
- public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {
- this.principals = new SimplePrincipalCollection(principal, realmName);
- this.credentials = hashedCredentials;
- this.credentialsSalt = credentialsSalt;
- }
这个和你加密的密码salt有关:
- package com.lgy.service;
-
- import org.apache.shiro.crypto.RandomNumberGenerator;
- import org.apache.shiro.crypto.SecureRandomNumberGenerator;
- import org.apache.shiro.crypto.hash.SimpleHash;
- import org.apache.shiro.util.ByteSource;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Service;
-
- import com.lgy.model.User;
-
- @Service
- public class PasswordHelper {
- private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
-
- @Value("${password.algorithmName}")
- private String algorithmName;
- @Value("${password.hashIterations}")
- private int hashIterations;
-
- public void encryptPassword(User user) {
-
- user.setSalt(randomNumberGenerator.nextBytes().toHex());
-
- String newPassword = new SimpleHash(
- algorithmName, //加密算法
- user.getPassword(), //密码
- ByteSource.Util.bytes(user.getCredentialsSalt()), //salt盐 username + salt
- hashIterations //迭代次数
- ).toHex();
-
- user.setPassword(newPassword);
- }
- }
所以它需要设置凭证信息:
-
- <bean id="userRealm" class="com.lgy.web.shiro.UserRealm">
-
- <property name="credentialsMatcher" ref="credentialsMatcher" />
- </bean>
-
-
- <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
-
- <property name="hashAlgorithmName" value="${password.algorithmName}" />
-
- <property name="hashIterations" value="${password.hashIterations}" />
- </bean>
若认证通过后,它会跳转到设置的辅助登录成功url是/first。身份认证到这里就结束咯!
授权过程如下:
shiro授权有三种方式:
1 编程式:通过写if/else 授权代码块完成:
Subject subject =SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
2 注解式:通过在执行的Java方法上放置相应的注解完成:
@RequiresRoles("admin")
public void hello() {
//有权限
}
3.JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
<shiro:hasRolename="admin">
<!— 有权限—>
</shiro:hasRole>
编程试的不用说了,重点说说注解方式和jsp标签方式:
若使用SpringMVC注解试,需要在SpringMVC的配置文件中配置注解启动:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:util="http://www.springframework.org/schema/util"
- xmlns:aop="http://www.springframework.org/schema/aop"
- 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
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <aop:config proxy-target-class="true"></aop:config>
- <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
- <property name="securityManager" ref="securityManager"/>
- </bean>
- </beans>
在控制器中:
- @RequiresPermissions("user:create")
- @RequestMapping(value = "/create", method = RequestMethod.GET)
- public String showCreateForm(Model model) {
- //...
- return "user/edit";
- }
当进入到这个Controller中的时候,会先进入realm中的:
- /**
- * 授权认证
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- User user = (User) principals.getPrimaryPrincipal();
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- authorizationInfo.setRoles(userService.findRoles(user.getUsername()));
- authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));
- return authorizationInfo;
- }
权限比较可能有如下2个:
@RequiresPermissions("user:create")
@RequiresRoles("admin")
1.基于角色的认证
2.基于权限码的认证
若使用jsp标签进行认证:
条件:需要导入shiro标签 <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
页面中
<shiro:hasPermission name="user:update">
......
</shiro:hasPermission>
<shiro:hasRole name="">
......
</shiro:hasRole>
同上进入该页面中时候,若出现这样的标签,每出现一个都会调用realm中的:
- /**
- * 授权认证
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- User user = (User) principals.getPrimaryPrincipal();
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- authorizationInfo.setRoles(userService.findRoles(user.getUsername()));
- authorizationInfo.setStringPermissions(userService.findPermissions(user.getUsername()));
- return authorizationInfo;
- }
相当于他们调用了shiro中的:
Subject subject = SecurityUtils.getSubject();
subject.checkRole("");
subject.checkPermission("");
*
shiro的jsp标签
Jsp页面添加:
<%@ tagliburi="http://shiro.apache.org/tags"prefix="shiro" %>
标签名称 |
标签条件(均是显示标签内容) |
<shiro:authenticated> |
登录之后 |
<shiro:notAuthenticated> |
不在登录状态时 |
<shiro:guest> |
用户在没有RememberMe时 |
<shiro:user> |
用户在RememberMe时 |
<shiro:hasAnyRoles name="abc,123" > |
在有abc或者123角色时 |
<shiro:hasRole name="abc"> |
拥有角色abc |
<shiro:lacksRole name="abc"> |
没有角色abc |
<shiro:hasPermission name="abc"> |
拥有权限资源abc |
<shiro:lacksPermission name="abc"> |
没有abc权限资源 |
<shiro:principal> |
显示用户身份名称 |
<shiro:principalproperty="username"/> 显示用户身份中的属性值
当然每次都这么做可能浪费性能很不好,这时侯就需要配置缓存。