您的位置:首页 > 其它

shiro权限框架中的认证和授权过程

2017-12-16 23:28 465 查看
[html] view
plain copy

</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

<!-- 对所有url都需要进行认证 -->

/logout = logout

&
1939f
nbsp; /** = authc //设置授权才能访问

</value>

</property>

</bean>

首先看一下Shiro中的web filter过滤器:

默认采用的认证过滤器filter是表单过滤器,默认登录的url是/login(只要没有认证的都会跳转到/login路径下),辅助登录成功url是/first。

默认登录url跳转到的页面是login.jsp如下:

[html] view
plain copy

<!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>

 
2fa0d
; <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中的方法进行身份认证:

[html] view
plain copy

/**

* 身份认证

*/

@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.

[html] view
plain copy

public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {

this.principals = new SimplePrincipalCollection(principal, realmName);

this.credentials = credentials;

}

构造器对应的默认任凭类,什么都不需要输入,没有加密算法,没有迭代次数,直接通过用户名和密码进行进行验证就可以。

[html] view
plain copy

<bean id="userRealm" class="com.lgy.web.shiro.UserRealm">

<!-- 设置认证凭证器 -->

<!--<property name="credentialsMatcher" ref="credentialsMatcher" /> -->

</bean>

2.

[html] view
plain copy

public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) {

this.principals = new SimplePrincipalCollection(principal, realmName);

this.credentials = hashedCredentials;

this.credentialsSalt = credentialsSalt;

}

这个和你加密的密码salt有关:

[html] view
plain copy

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);

}

}

所以它需要设置凭证信息:

[html] view
plain copy

<!-- Realm实现 -->

<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的配置文件中配置注解启动:

[html] view
plain copy

<?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>

在控制器中:

[html] view
plain copy

@RequiresPermissions("user:create")

@RequestMapping(value = "/create", method = RequestMethod.GET)

public String showCreateForm(Model model) {

//...

return "user/edit";

}

当进入到这个Controller中的时候,会先进入realm中的:

[html] view
plain copy

/**

* 授权认证

*/

@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中的:

[html] view
plain copy

/**

* 授权认证

*/

@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"/> 显示用户身份中的属性值
当然每次都这么做可能浪费性能很不好,这时侯就需要配置缓存。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: