本帖最后由 每天笑呵呵 于 2018-1-19 18:07 编辑
前言:权限管理是项目中不可缺少的一部分,它主要由两方面组成:认证和授权;它还有三个必备的实体类(5张表,类之间都是多对多的关系):User(用户)、Role(角色)、Permission(权限);它有两种主要控制方式:粗粒度URL级别的权限控制、细粒度的权限控制;这里将主要总结一下最近bos项目中的权限管理框架shiro的简单使用。
1.使用它首先就要导入jar包:(它有多个具体功能的jar包,这里直接使用全功能jar包)
<shiro.version>1.2.2</shiro.version>
<!-- 权限控制 框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>${shiro.version}</version>
</dependency>
2.shiro这个框架从你开始访问项目的时候就要进行权限控制,因此,便可以通过一个过滤器来实现。
web.xml中配置:
<!-- shiro的Filter -->
filter的名字不能乱起,必须是这个因为这个filter会拿这个名字去核心配置文件中找同名的bean
<filter>
<!-- 去spring配置文件中寻找同名bean -->
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.当过滤器拦截请求后,就可以进行权限控制了,第一步就是拿着自己过滤器的名字去spring核心配置文件中查找同名的bean
applicationContext-shiro.xml配置:
<!-- shiro filter配置 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- shiro 的核心安全接口 -->
<property name="securityManager" ref="securityManager" />
<!-- 要求登录时的链接 -->
<property name="loginUrl" value="/login.jsp" />
<!-- 登陆成功后要跳转的连接 -->
<property name="successUrl" value="/index.jsp" />
<!-- 未授权时要跳转的连接 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp" />
<!-- shiro 连接约束配置 -->
<!-- url级别权限权限控制 -->
<property name="filterChainDefinitions">
<value>
【anon是不验证也不拦截,一个*是指后面可以添加参数?username=...】
【authc:认证后可以访问;perms:需要特定权限才能访问;roles:需要特定角色才能访问;
user:需要特定用户才能访问;port:需要特定端口才能访问;reset:根据指定HTTP请求访问才能访问】
【这是登录界面所以要放行】
/login.jsp*=anon
【之所以放行这个action,是因为这个action是认证前访问,如果不放行,表单提交不了,又会回到登陆界面】
/user_login.action*=anon
【这个是登录页面验证码的jsp】
/validatecode.jsp*=anon
/unauthorized.jsp*=anon
/css/*=anon
/js/*=anon
/images/*=anon
/json/*=anon
【这是表示webService的路径也不必拦截,因为webService在web.xml中配置这个路径,两个*表示当前目录下所有文件文件夹】
/services/** = anon
/easyuidemo/*=anon
【粗粒度的权限控制】
【访问这个页面需要特定权限】
/page_base_staff.action*=perms["staff"]
【访问这个页面需要特定角色】
/page_base_region.action*=roles["base"]
/*=authc
</value>
</property>
</bean>
4.讲到这配置文件还没有配置完,先上一张图,说一下,再说一下前言中涉及的东西。
上图显示了shiro的三大组件,框架的执行流程:应用程序---Subject(框架管理的用户)----SecurityManager(底层调用,它是框架的核心)----Realm(程序与权限控制数据之间的连接器,读取安全数据(数据表、文件、网络))
后面的所有操作都是围绕着这个流程进行的,因此它是重中之重,必须掌握。
5.当你访问这个工程的时候,正如上面配置文件中设置一样,默认将页面导向login.html,因此只有登录才能够访问工程,账号密码输入,进入UserAction的login方法,
(1)将用户账号密码给Subject:
@Action(value = "user_login", results = {
@Result(name = "login", type = "redirect", location = "login.html"),
@Result(name = "success", type = "redirect", location = "index.html") })
public String login() {
// 用户名和密码 都保存在model中
// 基于shiro实现登录
Subject subject = SecurityUtils.getSubject();
// 用户名和密码信息
AuthenticationToken token = new UsernamePasswordToken(
model.getUsername(), model.getPassword());
try {
【这一步,将代码保存你登录输入的账号密码,底层调用了上图中的SecurityManager,这个类就在配置文件里,下面将添加这个bean】
subject.login(token);
// 登录成功
// 将用户信息 保存到 Session
return SUCCESS;
} catch (AuthenticationException e) {
// 登录失败
e.printStackTrace();
return LOGIN;
}
}
6.配置文件增加一个框架底层核心类,这个类拿到账号密码后就会通过Realm类来查询数据库,因此创建一个名为BosRealm的类
配置文件加上一段:
<!-- 安全管理器 -->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm" />
</bean>
<!-- 后处理器 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
编写Realm类:只需要继承Realm的子类AuthorizingRealm,这是一个抽象类,里面包含认证和授权方法,都是框架底层默认调用的。
【加@service是为了让spring扫描到这个类,将这个类注入到安全管理器的bean标签中】
@Service("bosRealm")【这写了名字,那么在配置文件属性注入时,ref写这个名字即可】
public class BosRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
@Override
// 授权...
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("shiro 授权管理...");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 根据当前登录用户 查询对应角色和权限
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
// 调用业务层,查询角色
List<Role> roles = roleService.findByUser(user);
for (Role role : roles) {
authorizationInfo.addRole(role.getKeyword());
}
// 调用业务层,查询权限
List<Permission> permissions = permissionService.findByUser(user);
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getKeyword());
}
//返回的就是权限信息
return authorizationInfo;
}
@Override
// 认证...
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("shiro 认证管理... ");
【这个token已经有了你登录时输入的的账号密码】
// 转换token
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 根据用户名 查询 用户信息,因为如果登录成功,需要将查询到的完整用户信息保存到Subject对象中,以后认证的时候需要用到uid
User user = userService.findByUsername(usernamePasswordToken
.getUsername());
if (user == null) {
// 用户名不存在
// 参数一: 期望登录后,保存在Subject中信息
// 参数二: 如果返回为null 说明用户不存在,会报用户名不存在异常org.apache.shiro.authc.UnknownAccountException
// 参数三 :realm名称
return null;
} else {
// 用户名存在
// 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
// 如果密码一致 登录成功, 如果密码不一致 报密码错误异常org.apache.shiro.authc.lncorrectCredentialsException
return new SimpleAuthenticationInfo(user, user.getPassword(),
getName());
}
}
}
7.上面配置文件中被标记为黑底白字的就是粗粒度url级别控制,如果要细粒度方法级别控制,需要配置文件增加shiro注解扫描和在需要权限的地方加上权限注解配置文件加上:
<!-- 开启shiro注解模式 -->
<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>
同时配置事务的配置文件也要修改这句,目的是使用cglab动态代理
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
方法上的注解:
@RequiresPermission("权限名"):需要特点权限才能访问
@RequiresRoles("角色名"):需要特点角色才能访问
|