认证和授权学习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
时就会被拦截到,并判断是否有对应的权限,如果有权限,可以正常访问,即对用户完成了授权,没有权限就拒绝访问表示不进行授权。
对访问请求的拦截也可以通过过滤器来实现,道理都是一样的。