Spring Integration shiro authorization

Authorize that the competence to verify, verify that a user has authenticated a privilege; that is to determine whether the user can do things such as common: verify that a user has a role. Or fine-grained verify whether a user has a permission for a resource.

::: tip Note

Note: Authorization is based on the basis of certification

:::

Authorization of three ways

  • Programming way: such as the use if the current subject has permission to determine whether this approach to determine the time has actually entered the house method.
  • Notes ways : add permissions annotation on methods for verification before entering the method.
  • jsp tags manner: shiro jsp tag provided by the user authority to determine whether the operation button or the like in accordance with display, if the request directly from the direct access url embodiment does not require authorization.

Authorization step

1. Add @RequirePermission comment on the approach requires authorization

When using annotations to note three points: ① comment itself, we must define a comment ② annotated classes, to comment on the method or class ③ on how to make annotations take effect

For example, I added to the list of queries @RequiresPermissions("user:list")annotation, it means that this method requires the user to have access rights llist user can access, otherwise it will throw an UnauthorizedExceptionexception.

2. Configure the proxy class analytical notes in spring-shiro file

    <!-- 开启aop,对类代理 -->
    <aop:config proxy-target-class="true"></aop:config>
    <!-- 开启shiro注解支持 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

::: warning Note:

I added this method in the Controller, this time in my UserRealm authorization information is empty, which means that the current user does not have any authority, but when I actually visited this method can also be a normal visit. . . . By Baidu Dafa find the answer to the question:


We know that comment is authorized Shiro Lee Spring's AOP has achieved. When the program starts automatically scans were annotated Class, when finding notes, automatically inject the authorization code. That is, the control code to be injected authorization, must make the frame at first to be scanned can find annotated Class.

spring.xml

<context:component-scan base-package="cn.edu.neusoft" >
    <context:exclude-filter type="annotation"        expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

spring-mvc.xml

<context:component-scan base-package="cn.edu.neusoft" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

Our Srping project in ApplicationContext.xml generally are not scanned Controller, it will not be able to make written notes from the Controller's authorization came into force. Therefore, the correct approach is to put into springmvc configuration profile. Such Controller can be authorized by the comment.

But the question is, by the above configuration Controller is authorized by the comment, but can not comment Services is still authorized. Although, if we control the authorization from the Controller, the Service layer for internal calls can no longer be authorized,

But there are exceptions, such as Service Controller layer in addition to internal calls, but also for remote SOAP call, you need to control the authorization of the Service. At the same time to control the Controller and Service, then the same way, we can configure similar configuration in ApplicationContext.xml in order to achieve the same effect.
:::

Configuration of exception handling Shiro

Because SpringMVC have a default exception handling mechanism, it is necessary to define the special rough Shiro exception handler to take effect, here is whether the authority if this exception redirected to this page nopermisson

<!--shiro权限异常处理-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.apache.shiro.authz.UnauthorizedException">redirect:/admin/system/nopermission</prop>
            </props>
        </property>
    </bean>

::: tip did not use ajax ignored here:

The first step here is complete, but encountered a problem, I am using ajax request, but not before the request to the Controller when the request had been intercepted, the response back to a nopermission this page, but there is not with ajax automatically jump to the page, very hard to accept. . .

It is addressed. . (Find a day finally resolved):

Reference article: https://blog.csdn.net/catoop/article/details/69210140

The principle is to BaseController through a unified process, then other Controller can be inherited, and JSON page for the jump, we just need to do a deal with Ajax judgment can be.

BaseController Code:

/**
 * @author Chen
 * @create 2019-05-02 19:26
*/
public abstract class BaseController {


 /**
     * 权限异常
  */
 @ExceptionHandler({ UnauthorizedException.class, AuthorizationException.class })
 public String authorizationException(HttpServletRequest request, HttpServletResponse response) {
     if (WebUtilsPro.isAjaxRequest(request)) {
         // 输出JSON
         Map<String,Objectmap = new HashMap<>();
         map.put("type", "error");
         map.put("msg", "无权限");
         writeJson(map, response);
         return null;
     } else {
         return "redirect:/system/403";
     }
 }

 /**
     * 输出JSON
  *
     * @param response
     * @author SHANHY
     * @create 2017年4月4日
  */
 private void writeJson(Map<String,Objectmap, HttpServletResponse response) {
     PrintWriter out = null;
     try {
         response.setCharacterEncoding("UTF-8");
         response.setContentType("application/json; charset=utf-8");
         out = response.getWriter();
         //这里用了一个阿里的fastjson,直接添加一下依赖即可
         out.write(String.valueOf(new JSONObject(map)));
     } catch (IOException e) {
         e.printStackTrace();
     } finally {
         if (out != null) {
             out.close();
         }
     }
 }
}

WebUtilsPro Code:

package cn.edu.neusoft.common;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Chen
 * @create 2019-05-02 19:27
*/
public class WebUtilsPro {

 /**
     * 是否是Ajax请求
  *
     * @param request
     * @return
     * @author SHANHY
     * @create 2017年4月4日
  */
 public static boolean isAjaxRequest(HttpServletRequest request) {
     String requestedWith = request.getHeader("x-requested-with");
     if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
         return true;
     } else {
         return false;
     }
 }
}

Then inherit this BaseController OK.
:::

4. Load rights expression

::: tip Description:
We comment on a number of methods are marked permissions, the user must have the rights to access, the user needs to have the authority to tell Shiro in the Realm, and so many ways will certainly be saved to the database, we can not go one by one is added to the database.

Let's add by acquiring properties of the annotation to the database stored in the database :( rights expression and authority name)

Since Shiro does not provide the name of the custom annotation privileges to us, so we customize a comment for obtaining permission to name added to the database.
:::
PermissionController:

/**
 * @author Chen
 * @create 2019-05-01 20:28
 */
@Controller
@RequestMapping("admin/permission")
public class PermissionController {

    @Autowired
    private PermissionService permissionService;

    //请求映射处理映射器
    //springmvc在启动时候将所有贴有请求映射标签:RequestMapper方法收集起来封装到该对象中
    @Autowired
    private RequestMappingHandlerMapping rmhm;


    @ResponseBody
    @RequestMapping("reload")
    public Map<String,Object> reload(){
        Map<String,Object> map = new HashMap<String, Object>();
        //将系统中所有权限表达式加载进入数据库
        //0:从数据库中查询出所有权限表达式,然后对比,如果已经存在了,跳过,不存在添加
        List<String> resourcesList = permissionService.getAllResources();
        //1:获取controller中所有带有@RequestMapper标签的方法
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = rmhm.getHandlerMethods();
        Collection<HandlerMethod> methods = handlerMethods.values();
        for (HandlerMethod method : methods) {
            //2:遍历所有方法,判断当前方法是否贴有@RequiresPermissions权限控制标签
            RequiresPermissions anno = method.getMethodAnnotation(RequiresPermissions.class);
            if(anno != null){
                //3:如果有,解析得到权限表达式,封装成Permission对象保存到Permission表中
                //权限表达式
                String resource = anno.value()[0];

                //去除重复的
                if(resourcesList.contains(resource)){
                    continue;
                }
                Permission p = new Permission();
                p.setResource(resource);
                //设置权限名称
                p.setName(method.getMethodAnnotation(PermissionName.class).value());
                //保存
                permissionService.addPermission(p);
            }
        }

        map.put("type","success");
        map.put("msg","加载成功!");
        return map;
    }



}

Notes category PermissionName

package cn.edu.neusoft.realm;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author Chen
 * @create 2019-05-01 20:20
 * 自定义权限名称注解
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionName {
    String value();
}

We just like to comment on the request to specify the path to load permissions to the database.

@RequiresPermissions("user:delete")
@PermissionName("用户删除")
public Map<String,Object> deleteUser(@RequestParam(required = true) Long id){
    ······

5. Integrated database authorization

Here you can put the role of the corresponding rights Shiro told him to judge whether the role is already registered have access to the

The method of modifying doGetAuthorizationInfo UserRealm class:

/**
 * @author Chen
 * @create 2019-04-30 15:27
 */
public class UserRealm extends AuthorizingRealm {
    @Setter
    private UserService userService;
    @Setter
    private RoleService roleService;
    @Setter
    private PermissionService permissionService;


    @Override
    public String getName() {
        return "UserRealm";
    }

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User) principalCollection.getPrimaryPrincipal();
        List<String> permissions = new ArrayList<String>();
        List<String> roles = new ArrayList<String>();

        if ("admin".equals(user.getUsername())){
            //让超级管理员拥有所有权限
            permissions.add("*:*");
            //查询所有角色
            roles = roleService.getRoleByUserId(user.getId());
        }else {
            //根据用户ID查询该用户具有的角色
            roles = roleService.getRoleByUserId(user.getId());
            //根据用户ID查询该用户具有的权限
            permissions = permissionService.getAllPermissionsByUserId(user.getId());
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);
        info.addRoles(roles);
        return info;
    }

    /**
     * 认证
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //从token中获取登录的用户名, 查询数据库返回用户信息
        String username = (String) token.getPrincipal();
        User user = userService.getUserByUsername(username);

        if (user == null) {
            return null;
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        return info;
    }

}

Do not forget to inject corresponding Service in Spring-shiro.xml

Here used according to the user ID information and permission information query role of multi-table queries, incidentally brushed up, click on the link below need:

http://ishangit.cn/?id=54

In the sql statement corresponding to impress:

<select id="getAllPermissionsByUserId" parameterType="Long" resultType="String">
        select resource from user u
        join user_role ur on u.id = ur.user_id
        join role_permission rp on ur.role_id = rp.role_id
        join permission p on rp.permission_id = p.id
        where u.id = #{id}
    </select>
<mapper namespace="cn.edu.neusoft.dao.RoleDao">
    <select id="getRoleByUserId" resultType="String" parameterType="Long">
        select sn from role r 
        join user_role u on r.id = u.role_id where user_id = #{id}
    </select>

Here we entitlements feature to complete it.

Guess you like

Origin www.cnblogs.com/chen88/p/11538363.html