认证和授权学习1基于session的认证授权流程

一、什么是认证

用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信 息,身份合法方可继续访问,不合法则拒绝访问

二、什么是授权

授权是用户认证通过后,根据用户的权限来控制用户对访问资源的过程,拥有资源的访问权限则正常访问,没有 权限则拒绝访问。

授权可以理解为主体(用户)对资源的受限操作

三、基于session的认证授权流程

用户携带账号密码请求登录,登录成功后服务端生成用户信息对象保存在session中,把sessionId存到cookie中返回给客户端;当客户端再次访问时携带cookie信息,服务端判断session中是否存有用户信息,如果没有表示未登录,如果有根据session中用户信息的权限信息完成授权。用户退出时清空session信息

用户登录时携带的账号密码等信息可以封装到一个参数对象中,


/**
 * 认证请求参数
 */
@Data
public class AuthenticationRequest {

    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
}

登录成功后存放到session中的用户信息也可以定义一个对象


/**
 * 当前登录用户信息
 */
@Data
@AllArgsConstructor
public class UserDto {
    public final static String SESSION_USER_KEY ="_USER";
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
    /**
     * 用户权限
     */
    private Set<String> authorities;
}

可以定义一个校验接口来校验用户是否能登录成功


/**
 * 认证服务
 */
public interface AuthenticationService {
    /**
     * 用户认证
     * @param authenticationRequest 用户认证请求
     * @return 认证成功的用户信息
     */
    UserDto authentication(AuthenticationRequest authenticationRequest);
}

校验方法的实现

@Override
public UserDto authentication(AuthenticationRequest authenticationRequest) {
        if (authenticationRequest == null
                || StringUtils.isEmpty(authenticationRequest.getUsername())
                || StringUtils.isEmpty(authenticationRequest.getPassword())) {
            throw new RuntimeException("账号或密码为空");
        }
        UserDto userDto = getUserDto(authenticationRequest.getUsername());
        if (userDto == null) {
            throw new RuntimeException("查询不到该用户");
        }
        if (!authenticationRequest.getPassword().equals(userDto.getPassword())) {
            throw new RuntimeException("账号或密码错误");
        }
        return userDto;
    }

其中getUserDto方法用来根据传入的用户名到数据库中查询用户对象

定义一个controller来处理登录请求

@RestController
public class LoginController {

    @Autowired
    private AuthenticationService authenticationService;

    @PostMapping(value = "/login",produces = {"text/plain;charset=UTF-8"})
    public String login(AuthenticationRequest authenticationRequest, HttpServletRequest request){
        UserDto userDto = authenticationService.authentication(authenticationRequest);
        //登录成功后把当前用户信息保存到session中
        request.getSession().setAttribute(UserDto.SESSION_USER_KEY,userDto);
        return userDto.getFullname()+"登录成功";
    }

    @GetMapping( value = "/logout",produces = {"text/plain;charset=UTF-8"})
    public String logout(HttpServletRequest request){
        //让session失效
        request.getSession().invalidate();
        return "退出成功";
    }
}

这样就完成了用户的认证过程。在用户访问某个系统资源时需要判断是否有对应的权限,即授权流程,可以通过springmvc的拦截器来对请求进行拦截


/**
 * 权限控制拦截器
 */
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //读取会话信息
        Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
        if (null == object) {
            writeContent(response, "请登录");
        }

        UserDto user = (UserDto) object;
        //请求的url
        String requestURI = request.getRequestURI();

        //对r1和r2两个资源的访问进行控制
        if(user.getAuthorities().contains("p1") && requestURI.contains("/r1")){
            return true;
        }
        if(user.getAuthorities().contains("p2") && requestURI.contains("/r2")){
            return true;
        }
        writeContent(response,"权限不足,拒绝访问");
        return false;
    }

    //向前端响应信息
    private void writeContent(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("text/plain;charset=UTF-8");//注意这个utf-8要是大写,小写的时候前端会乱码
        PrintWriter writer = response.getWriter();
        writer.print(msg);
        writer.close();
        response.resetBuffer();
    }
}

配置这个自定义拦截器到系统中,并指定拦截路径为需要受保护的资源路径,如/r/**,这样当用户访问/r/r1或者/r/r2时就会被拦截到,并判断是否有对应的权限,如果有权限,可以正常访问,即对用户完成了授权,没有权限就拒绝访问表示不进行授权。

对访问请求的拦截也可以通过过滤器来实现,道理都是一样的。